feat(测试跟踪): 禅道插件化改造
This commit is contained in:
parent
39defe8a3b
commit
90bbdc168a
|
@ -6,6 +6,7 @@ import io.metersphere.base.mapper.PluginMapper;
|
||||||
import io.metersphere.commons.constants.StorageConstants;
|
import io.metersphere.commons.constants.StorageConstants;
|
||||||
import io.metersphere.metadata.service.FileManagerService;
|
import io.metersphere.metadata.service.FileManagerService;
|
||||||
import io.metersphere.metadata.vo.FileRequest;
|
import io.metersphere.metadata.vo.FileRequest;
|
||||||
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@ -28,6 +29,17 @@ public class BasePluginService {
|
||||||
return pluginMapper.selectByExampleWithBLOBs(example);
|
return pluginMapper.selectByExampleWithBLOBs(example);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PluginWithBLOBs get(String pluginId) {
|
||||||
|
return pluginMapper.selectByPrimaryKey(pluginId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PluginWithBLOBs getByScripId(String scripId) {
|
||||||
|
PluginExample example = new PluginExample();
|
||||||
|
example.createCriteria().andScriptIdEqualTo(scripId);
|
||||||
|
List<PluginWithBLOBs> plugins = pluginMapper.selectByExampleWithBLOBs(example);
|
||||||
|
return CollectionUtils.isEmpty(plugins) ? null : plugins.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
public InputStream getPluginResource(String pluginId, String resourceName) {
|
public InputStream getPluginResource(String pluginId, String resourceName) {
|
||||||
FileRequest request = new FileRequest();
|
FileRequest request = new FileRequest();
|
||||||
request.setProjectId(DIR_PATH + "/" + pluginId);
|
request.setProjectId(DIR_PATH + "/" + pluginId);
|
||||||
|
@ -38,6 +50,9 @@ public class BasePluginService {
|
||||||
|
|
||||||
public InputStream getPluginJar(String pluginId) {
|
public InputStream getPluginJar(String pluginId) {
|
||||||
PluginWithBLOBs plugin = pluginMapper.selectByPrimaryKey(pluginId);
|
PluginWithBLOBs plugin = pluginMapper.selectByPrimaryKey(pluginId);
|
||||||
|
if (plugin == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return getPluginResource(pluginId, plugin.getSourceName());
|
return getPluginResource(pluginId, plugin.getSourceName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,6 @@ public class IssuesDao extends IssuesWithBLOBs {
|
||||||
private List<String> caseIds;
|
private List<String> caseIds;
|
||||||
private String caseId;
|
private String caseId;
|
||||||
private List<String> tapdUsers;
|
private List<String> tapdUsers;
|
||||||
private List<String>zentaoBuilds;
|
|
||||||
private String zentaoAssigned;
|
|
||||||
private String refType;
|
private String refType;
|
||||||
private String refId;
|
private String refId;
|
||||||
private List<CustomFieldDao> fields;
|
private List<CustomFieldDao> fields;
|
||||||
|
|
|
@ -21,14 +21,6 @@ public class IssuesRequest extends BaseQueryRequest {
|
||||||
* 如果是 PLAN_FUNCTIONAL 则只查询该测试计划用例所关联的缺陷
|
* 如果是 PLAN_FUNCTIONAL 则只查询该测试计划用例所关联的缺陷
|
||||||
*/
|
*/
|
||||||
private String refType;
|
private String refType;
|
||||||
/**
|
|
||||||
* zentao bug 处理人
|
|
||||||
*/
|
|
||||||
private String zentaoUser;
|
|
||||||
/**
|
|
||||||
* zentao bug 影响版本
|
|
||||||
*/
|
|
||||||
private List<String> zentaoBuilds;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* issues id
|
* issues id
|
||||||
|
|
|
@ -22,15 +22,6 @@ public class IssuesUpdateRequest extends IssuesWithBLOBs {
|
||||||
private List<CustomFieldResourceDTO> addFields;
|
private List<CustomFieldResourceDTO> addFields;
|
||||||
private List<CustomFieldResourceDTO> editFields;
|
private List<CustomFieldResourceDTO> editFields;
|
||||||
private List<CustomFieldItemDTO> requestFields;
|
private List<CustomFieldItemDTO> requestFields;
|
||||||
/**
|
|
||||||
* zentao bug 处理人
|
|
||||||
*/
|
|
||||||
private String zentaoUser;
|
|
||||||
private String zentaoAssigned;
|
|
||||||
/**
|
|
||||||
* zentao bug 影响版本
|
|
||||||
*/
|
|
||||||
private List<String> zentaoBuilds;
|
|
||||||
private boolean thirdPartPlatform;
|
private boolean thirdPartPlatform;
|
||||||
|
|
||||||
private List<String> follows;
|
private List<String> follows;
|
||||||
|
|
|
@ -55,6 +55,9 @@ public class PluginManagerUtil {
|
||||||
* @param pluginManager
|
* @param pluginManager
|
||||||
*/
|
*/
|
||||||
public static void loadPlugin(String id, PluginManager pluginManager, InputStream inputStream) {
|
public static void loadPlugin(String id, PluginManager pluginManager, InputStream inputStream) {
|
||||||
|
if (inputStream == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (pluginManager == null) {
|
if (pluginManager == null) {
|
||||||
pluginManager = new PluginManager();
|
pluginManager = new PluginManager();
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,15 +31,14 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TapdSetting from '@/business/workspace/integration/TapdSetting';
|
import TapdSetting from '@/business/workspace/integration/TapdSetting';
|
||||||
import JiraSetting from '@/business/workspace/integration/JiraSetting';
|
|
||||||
import AzuredevopsSetting from '@/business/workspace/integration/AzureDevopsSetting';
|
import AzuredevopsSetting from '@/business/workspace/integration/AzureDevopsSetting';
|
||||||
import {AZURE_DEVOPS, TAPD, ZEN_TAO} from "metersphere-frontend/src/utils/constants";
|
import {AZURE_DEVOPS, TAPD} from "metersphere-frontend/src/utils/constants";
|
||||||
import PlatformConfig from "@/business/workspace/integration/PlatformConfig";
|
import PlatformConfig from "@/business/workspace/integration/PlatformConfig";
|
||||||
import {generatePlatformResourceUrl, getIntegrationInfo} from "@/api/platform-plugin";
|
import {generatePlatformResourceUrl, getIntegrationInfo} from "@/api/platform-plugin";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "BugManagement",
|
name: "BugManagement",
|
||||||
components: {PlatformConfig, TapdSetting, JiraSetting, AzuredevopsSetting},
|
components: {PlatformConfig, TapdSetting, AzuredevopsSetting},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading: false,
|
loading: false,
|
||||||
|
|
|
@ -1,229 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div style="width: 500px">
|
|
||||||
<div style="margin-top: 20px;margin-bottom: 10px">{{ $t('organization.integration.basic_auth_info') }}</div>
|
|
||||||
<el-form :model="form" ref="form" label-width="100px" size="small" :disabled="show" :rules="rules">
|
|
||||||
<el-form-item :label="$t('organization.integration.account')" prop="account">
|
|
||||||
<el-input v-model="form.account" :placeholder="$t('organization.integration.input_api_account')"/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="Token" prop="password">
|
|
||||||
<el-input v-model="form.password" auto-complete="new-password" v-if="showInput"
|
|
||||||
:placeholder="$t('organization.integration.input_api_password')" show-password/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t('organization.integration.jira_url')" prop="url">
|
|
||||||
<el-input v-model="form.url" :placeholder="$t('organization.integration.input_jira_url')"/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<bug-manage-btn @save="save"
|
|
||||||
@init="init"
|
|
||||||
:edit-permission="['WORKSPACE_SERVICE:READ+EDIT']"
|
|
||||||
@testConnection="testConnection"
|
|
||||||
@cancelIntegration="cancelIntegration"
|
|
||||||
@reloadPassInput="reloadPassInput"
|
|
||||||
:form="form"
|
|
||||||
:show.sync="show"
|
|
||||||
ref="bugBtn"/>
|
|
||||||
|
|
||||||
<div class="defect-tip">
|
|
||||||
<div>{{ $t('organization.integration.use_tip') }}</div>
|
|
||||||
<div>
|
|
||||||
1. {{ $t('organization.integration.use_tip_jira') }}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
2. {{ $t('organization.integration.use_tip_two') }}
|
|
||||||
<router-link to="/setting/project/all" style="margin-left: 5px;color: #551A8B; text-decoration: underline; cursor: pointer">
|
|
||||||
{{ $t('organization.integration.link_the_project_now') }}
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
3. {{ $t('organization.integration.use_tip_three') }}
|
|
||||||
<span style="margin-left: 5px;color: #551A8B; text-decoration: underline; cursor: pointer" @click="resVisible = true">
|
|
||||||
{{ $t('organization.integration.link_the_info_now') }}
|
|
||||||
</span>
|
|
||||||
<el-dialog :close-on-click-modal="false" width="80%"
|
|
||||||
:visible.sync="resVisible" destroy-on-close @close="closeDialog">
|
|
||||||
<ms-person-router @closeDialog = "closeDialog"/>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import BugManageBtn from "./BugManageBtn";
|
|
||||||
import {getCurrentUser, getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
|
|
||||||
import {JIRA} from "metersphere-frontend/src/utils/constants";
|
|
||||||
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
|
|
||||||
import MsPersonRouter from "metersphere-frontend/src/components/personal/PersonRouter";
|
|
||||||
import {
|
|
||||||
authServiceIntegration,
|
|
||||||
delServiceIntegration,
|
|
||||||
getServiceIntegration,
|
|
||||||
saveServiceIntegration
|
|
||||||
} from "../../../api/workspace";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "JiraSetting",
|
|
||||||
components: {MsInstructionsIcon, BugManageBtn,MsPersonRouter},
|
|
||||||
created() {
|
|
||||||
this.init();
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
show: true,
|
|
||||||
showInput: true,
|
|
||||||
resVisible:false,
|
|
||||||
form: {},
|
|
||||||
rules: {
|
|
||||||
account: {
|
|
||||||
required: true,
|
|
||||||
message: this.$t('organization.integration.input_api_account'),
|
|
||||||
trigger: ['change', 'blur']
|
|
||||||
},
|
|
||||||
password: {
|
|
||||||
required: true,
|
|
||||||
message: this.$t('organization.integration.input_api_password'),
|
|
||||||
trigger: ['change', 'blur']
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
required: true,
|
|
||||||
message: this.$t('organization.integration.input_jira_url'),
|
|
||||||
trigger: ['change', 'blur']
|
|
||||||
},
|
|
||||||
issuetype: {
|
|
||||||
required: true,
|
|
||||||
message: this.$t('organization.integration.input_jira_issuetype'),
|
|
||||||
trigger: ['change', 'blur']
|
|
||||||
},
|
|
||||||
storytype: {
|
|
||||||
required: true,
|
|
||||||
message: this.$t('organization.integration.input_jira_storytype'),
|
|
||||||
trigger: ['change', 'blur']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
init() {
|
|
||||||
const {lastWorkspaceId} = getCurrentUser();
|
|
||||||
let param = {};
|
|
||||||
param.platform = JIRA;
|
|
||||||
param.workspaceId = lastWorkspaceId;
|
|
||||||
this.$parent.loading = getServiceIntegration(param).then(res => {
|
|
||||||
let data = res.data;
|
|
||||||
if (data.configuration) {
|
|
||||||
let config = JSON.parse(data.configuration);
|
|
||||||
this.$set(this.form, 'account', config.account);
|
|
||||||
this.$set(this.form, 'password', config.password);
|
|
||||||
this.$set(this.form, 'url', config.url);
|
|
||||||
this.$set(this.form, 'issuetype', config.issuetype);
|
|
||||||
this.$set(this.form, 'storytype', config.storytype);
|
|
||||||
} else {
|
|
||||||
this.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
save() {
|
|
||||||
this.$refs['form'].validate(valid => {
|
|
||||||
if (valid) {
|
|
||||||
let formatUrl = this.form.url.trim();
|
|
||||||
if (!formatUrl.endsWith('/')) {
|
|
||||||
formatUrl = formatUrl + '/';
|
|
||||||
}
|
|
||||||
let param = {};
|
|
||||||
let auth = {
|
|
||||||
account: this.form.account,
|
|
||||||
password: this.form.password,
|
|
||||||
url: formatUrl,
|
|
||||||
issuetype: this.form.issuetype,
|
|
||||||
storytype: this.form.storytype
|
|
||||||
};
|
|
||||||
const {lastWorkspaceId} = getCurrentUser();
|
|
||||||
param.workspaceId = lastWorkspaceId;
|
|
||||||
param.platform = JIRA;
|
|
||||||
param.configuration = JSON.stringify(auth);
|
|
||||||
this.$parent.loading = saveServiceIntegration(param).then(() => {
|
|
||||||
this.show = true;
|
|
||||||
this.$refs.bugBtn.showEdit = true;
|
|
||||||
this.$refs.bugBtn.showSave = false;
|
|
||||||
this.$refs.bugBtn.showCancel = false;
|
|
||||||
this.reloadPassInput();
|
|
||||||
this.init();
|
|
||||||
this.$success(this.$t('commons.save_success'));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
clear() {
|
|
||||||
this.$set(this.form, 'account', '');
|
|
||||||
this.$set(this.form, 'password', '');
|
|
||||||
this.$set(this.form, 'url', '');
|
|
||||||
this.$set(this.form, 'issuetype', '');
|
|
||||||
this.$set(this.form, 'storytype', '');
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (this.$refs.form) {
|
|
||||||
this.$refs.form.clearValidate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
testConnection() {
|
|
||||||
if (this.form.account && this.form.password) {
|
|
||||||
this.$parent.loading = authServiceIntegration(getCurrentWorkspaceId(), JIRA).then(() => {
|
|
||||||
this.$success(this.$t('organization.integration.verified'));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.$warning(this.$t('organization.integration.not_integrated'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cancelIntegration() {
|
|
||||||
if (this.form.account && this.form.password) {
|
|
||||||
this.$alert(this.$t('organization.integration.cancel_confirm') + JIRA + "?", '', {
|
|
||||||
confirmButtonText: this.$t('commons.confirm'),
|
|
||||||
callback: (action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
const {lastWorkspaceId} = getCurrentUser();
|
|
||||||
let param = {};
|
|
||||||
param.workspaceId = lastWorkspaceId;
|
|
||||||
param.platform = JIRA;
|
|
||||||
this.$parent.loading = delServiceIntegration(param).then(() => {
|
|
||||||
this.$success(this.$t('organization.integration.successful_operation'));
|
|
||||||
this.init('');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.$warning(this.$t('organization.integration.not_integrated'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
reloadPassInput() {
|
|
||||||
this.showInput = false;
|
|
||||||
this.$nextTick(function () {
|
|
||||||
this.showInput = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
closeDialog(){
|
|
||||||
this.resVisible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.defect-tip {
|
|
||||||
background: #EDEDED;
|
|
||||||
border: solid #E1E1E1 1px;
|
|
||||||
margin: 10px 0;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-input {
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -1,235 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<div style="width: 500px">
|
|
||||||
<div style="margin-top: 20px;margin-bottom: 10px">{{ $t('organization.integration.basic_auth_info') }}</div>
|
|
||||||
<el-form :model="form" ref="form" label-width="100px" size="small" :disabled="show" :rules="rules">
|
|
||||||
<el-form-item :label="$t('organization.integration.account')" prop="account">
|
|
||||||
<el-input v-model="form.account" :placeholder="$t('organization.integration.input_api_account')"/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t('organization.integration.password')" prop="password">
|
|
||||||
<el-input v-model="form.password" auto-complete="new-password" v-if="showInput"
|
|
||||||
:placeholder="$t('organization.integration.input_api_password')" show-password/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t('organization.integration.zentao_url')" prop="url">
|
|
||||||
<el-input v-model="form.url" :placeholder="$t('organization.integration.input_zentao_url')"/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item :label="$t('organization.integration.zentao_request')" prop="request">
|
|
||||||
<el-radio v-model="form.request" label="PATH_INFO" size="small" border> PATH_INFO</el-radio>
|
|
||||||
<el-radio v-model="form.request" label="GET" size="small" border>GET</el-radio>
|
|
||||||
<ms-instructions-icon effect="light" style="margin-left: -20px;">
|
|
||||||
{{ $t('organization.integration.zentao_config_tip')}} <br/><br/>
|
|
||||||
{{ $t('organization.integration.zentao_config_path')}}
|
|
||||||
</ms-instructions-icon>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<bug-manage-btn @save="save"
|
|
||||||
@init="init"
|
|
||||||
:edit-permission="['WORKSPACE_SERVICE:READ+EDIT']"
|
|
||||||
@testConnection="testConnection"
|
|
||||||
@cancelIntegration="cancelIntegration"
|
|
||||||
@reloadPassInput="reloadPassInput"
|
|
||||||
:form="form"
|
|
||||||
:show.sync="show"
|
|
||||||
ref="bugBtn"/>
|
|
||||||
|
|
||||||
<div class="defect-tip">
|
|
||||||
<div>{{ $t('organization.integration.use_tip') }}</div>
|
|
||||||
<div>
|
|
||||||
1. {{ $t('organization.integration.use_tip_zentao') }}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
2. {{ $t('organization.integration.use_tip_two') }}
|
|
||||||
<router-link to="/setting/project/all" style="margin-left: 5px;color: #551A8B; text-decoration: underline; cursor: pointer">
|
|
||||||
{{ $t('organization.integration.link_the_project_now') }}
|
|
||||||
</router-link>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
3. {{ $t('organization.integration.use_tip_three') }}
|
|
||||||
<span style="margin-left: 5px;color: #551A8B; text-decoration: underline; cursor: pointer" @click="resVisible = true">
|
|
||||||
{{ $t('organization.integration.link_the_info_now') }}
|
|
||||||
</span>
|
|
||||||
<el-dialog :close-on-click-modal="false" width="80%"
|
|
||||||
:visible.sync="resVisible" destroy-on-close @close="closeDialog">
|
|
||||||
<ms-person-router @closeDialog = "closeDialog"/>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import BugManageBtn from "./BugManageBtn";
|
|
||||||
import {getCurrentUser, getCurrentWorkspaceId} from "metersphere-frontend/src/utils/token";
|
|
||||||
import {ZEN_TAO} from "metersphere-frontend/src/utils/constants";
|
|
||||||
import MsInstructionsIcon from "metersphere-frontend/src/components/MsInstructionsIcon";
|
|
||||||
import MsPersonRouter from "metersphere-frontend/src/components/personal/PersonRouter";
|
|
||||||
import {
|
|
||||||
authServiceIntegration,
|
|
||||||
delServiceIntegration,
|
|
||||||
getServiceIntegration,
|
|
||||||
saveServiceIntegration
|
|
||||||
} from "../../../api/workspace";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "ZentaoSetting",
|
|
||||||
components: {
|
|
||||||
MsInstructionsIcon,
|
|
||||||
BugManageBtn,
|
|
||||||
MsPersonRouter
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.init();
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
show: true,
|
|
||||||
showInput: true,
|
|
||||||
resVisible:false,
|
|
||||||
form: {},
|
|
||||||
rules: {
|
|
||||||
account: {
|
|
||||||
required: true,
|
|
||||||
message: this.$t('organization.integration.input_api_account'),
|
|
||||||
trigger: ['change', 'blur']
|
|
||||||
},
|
|
||||||
password: {
|
|
||||||
required: true,
|
|
||||||
message: this.$t('organization.integration.input_api_password'),
|
|
||||||
trigger: ['change', 'blur']
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
required: true,
|
|
||||||
message: this.$t('organization.integration.input_zentao_url'),
|
|
||||||
trigger: ['change', 'blur']
|
|
||||||
},
|
|
||||||
request: {
|
|
||||||
required: true,
|
|
||||||
message: this.$t('organization.integration.input_zentao_request'),
|
|
||||||
trigger: ['change', 'blur']
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
save() {
|
|
||||||
this.$refs['form'].validate(valid => {
|
|
||||||
if (valid) {
|
|
||||||
let formatUrl = this.form.url.trim();
|
|
||||||
if (!formatUrl.endsWith('/')) {
|
|
||||||
formatUrl = formatUrl + '/';
|
|
||||||
}
|
|
||||||
const {lastWorkspaceId} = getCurrentUser();
|
|
||||||
let param = {};
|
|
||||||
let auth = {
|
|
||||||
account: this.form.account,
|
|
||||||
password: this.form.password,
|
|
||||||
url: formatUrl,
|
|
||||||
request: this.form.request
|
|
||||||
};
|
|
||||||
param.workspaceId = lastWorkspaceId;
|
|
||||||
param.platform = ZEN_TAO;
|
|
||||||
param.configuration = JSON.stringify(auth);
|
|
||||||
this.$parent.loading = saveServiceIntegration(param).then(() => {
|
|
||||||
this.show = true;
|
|
||||||
this.$refs.bugBtn.showEdit = true;
|
|
||||||
this.$refs.bugBtn.showSave = false;
|
|
||||||
this.$refs.bugBtn.showCancel = false;
|
|
||||||
this.reloadPassInput();
|
|
||||||
this.init();
|
|
||||||
this.$success(this.$t('commons.save_success'));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
init() {
|
|
||||||
const {lastWorkspaceId} = getCurrentUser();
|
|
||||||
let param = {};
|
|
||||||
param.platform = ZEN_TAO;
|
|
||||||
param.workspaceId = lastWorkspaceId;
|
|
||||||
this.$parent.loading = getServiceIntegration(param).then(res => {
|
|
||||||
let data = res.data;
|
|
||||||
if (data.configuration) {
|
|
||||||
let config = JSON.parse(data.configuration);
|
|
||||||
this.$set(this.form, 'account', config.account);
|
|
||||||
this.$set(this.form, 'password', config.password);
|
|
||||||
this.$set(this.form, 'url', config.url);
|
|
||||||
this.$set(this.form, 'request', config.request ? config.request : 'PATH_INFO');
|
|
||||||
} else {
|
|
||||||
this.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
clear() {
|
|
||||||
this.$set(this.form, 'account', '');
|
|
||||||
this.$set(this.form, 'password', '');
|
|
||||||
this.$set(this.form, 'url', '');
|
|
||||||
this.$set(this.form, 'request', '');
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (this.$refs.form) {
|
|
||||||
this.$refs.form.clearValidate();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
testConnection() {
|
|
||||||
this.$refs['form'].validate(valid => {
|
|
||||||
if (valid) {
|
|
||||||
if (this.form.account && this.form.password) {
|
|
||||||
this.$parent.loading = authServiceIntegration(getCurrentWorkspaceId(), ZEN_TAO).then(() => {
|
|
||||||
this.$success(this.$t('organization.integration.verified'));
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.$warning(this.$t('organization.integration.not_integrated'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
cancelIntegration() {
|
|
||||||
if (this.form.account && this.form.password) {
|
|
||||||
this.$alert(this.$t('organization.integration.cancel_confirm') + ZEN_TAO + "?", '', {
|
|
||||||
confirmButtonText: this.$t('commons.confirm'),
|
|
||||||
callback: (action) => {
|
|
||||||
if (action === 'confirm') {
|
|
||||||
const {lastWorkspaceId} = getCurrentUser();
|
|
||||||
let param = {};
|
|
||||||
param.workspaceId = lastWorkspaceId;
|
|
||||||
param.platform = ZEN_TAO;
|
|
||||||
this.$parent.loading = delServiceIntegration(param).then(() => {
|
|
||||||
this.$success(this.$t('organization.integration.successful_operation'));
|
|
||||||
this.init('');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.$warning(this.$t('organization.integration.not_integrated'));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
reloadPassInput() {
|
|
||||||
this.showInput = false;
|
|
||||||
this.$nextTick(function () {
|
|
||||||
this.showInput = true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
closeDialog(){
|
|
||||||
this.resVisible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.defect-tip {
|
|
||||||
background: #EDEDED;
|
|
||||||
border: solid #E1E1E1 1px;
|
|
||||||
margin: 10px 0;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -152,7 +152,7 @@
|
||||||
when 'textarea' then cfi.text_value
|
when 'textarea' then cfi.text_value
|
||||||
else cfi.value end as value
|
else cfi.value end as value
|
||||||
from custom_field_issues cfi
|
from custom_field_issues cfi
|
||||||
join custom_field cf on cf.id = cfi.field_id
|
left join custom_field cf on cf.id = cfi.field_id
|
||||||
where cfi.resource_id = #{issueId}
|
where cfi.resource_id = #{issueId}
|
||||||
</select>
|
</select>
|
||||||
<select id="getPlatformIssueByIds" resultType="io.metersphere.xpack.track.dto.IssuesDao">
|
<select id="getPlatformIssueByIds" resultType="io.metersphere.xpack.track.dto.IssuesDao">
|
||||||
|
|
|
@ -11,6 +11,7 @@ import io.metersphere.commons.constants.OperLogModule;
|
||||||
import io.metersphere.commons.constants.PermissionConstants;
|
import io.metersphere.commons.constants.PermissionConstants;
|
||||||
import io.metersphere.commons.utils.PageUtils;
|
import io.metersphere.commons.utils.PageUtils;
|
||||||
import io.metersphere.commons.utils.Pager;
|
import io.metersphere.commons.utils.Pager;
|
||||||
|
import io.metersphere.dto.CustomFieldDao;
|
||||||
import io.metersphere.dto.IssuesStatusCountDao;
|
import io.metersphere.dto.IssuesStatusCountDao;
|
||||||
import io.metersphere.excel.domain.ExcelResponse;
|
import io.metersphere.excel.domain.ExcelResponse;
|
||||||
import io.metersphere.log.annotation.MsAuditLog;
|
import io.metersphere.log.annotation.MsAuditLog;
|
||||||
|
@ -24,7 +25,6 @@ import io.metersphere.request.testcase.IssuesCountRequest;
|
||||||
import io.metersphere.service.BaseCheckPermissionService;
|
import io.metersphere.service.BaseCheckPermissionService;
|
||||||
import io.metersphere.service.IssuesService;
|
import io.metersphere.service.IssuesService;
|
||||||
import io.metersphere.service.PlatformPluginService;
|
import io.metersphere.service.PlatformPluginService;
|
||||||
import io.metersphere.service.issue.domain.zentao.ZentaoBuild;
|
|
||||||
import io.metersphere.xpack.track.dto.*;
|
import io.metersphere.xpack.track.dto.*;
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
||||||
|
@ -150,16 +150,6 @@ public class IssuesController {
|
||||||
return issuesService.getTapdProjectUsers(request);
|
return issuesService.getTapdProjectUsers(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/zentao/user")
|
|
||||||
public List<PlatformUser> getZentaoUsers(@RequestBody IssuesRequest request) {
|
|
||||||
return issuesService.getZentaoUsers(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/zentao/builds")
|
|
||||||
public List<ZentaoBuild> getZentaoBuilds(@RequestBody IssuesRequest request) {
|
|
||||||
return issuesService.getZentaoBuilds(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/sync/{projectId}")
|
@GetMapping("/sync/{projectId}")
|
||||||
public boolean syncThirdPartyIssues(@PathVariable String projectId) {
|
public boolean syncThirdPartyIssues(@PathVariable String projectId) {
|
||||||
return issuesService.syncThirdPartyIssues(projectId);
|
return issuesService.syncThirdPartyIssues(projectId);
|
||||||
|
@ -200,6 +190,11 @@ public class IssuesController {
|
||||||
return issuesService.getThirdPartTemplate(projectId);
|
return issuesService.getThirdPartTemplate(projectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/plugin/custom/fields/{projectId}")
|
||||||
|
public List<CustomFieldDao> getPluginCustomFields(@PathVariable String projectId) {
|
||||||
|
return issuesService.getPluginCustomFields(projectId);
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/demand/list/{projectId}")
|
@GetMapping("/demand/list/{projectId}")
|
||||||
public List getDemandList(@PathVariable String projectId) {
|
public List getDemandList(@PathVariable String projectId) {
|
||||||
return issuesService.getDemandList(projectId);
|
return issuesService.getDemandList(projectId);
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package io.metersphere.dto;
|
||||||
|
|
||||||
|
import io.metersphere.platform.domain.SelectOption;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class ThirdPartIssueField {
|
||||||
|
private String name;
|
||||||
|
private String type;
|
||||||
|
private String defaultValue;
|
||||||
|
private boolean required;
|
||||||
|
private String optionMethod;
|
||||||
|
private List<SelectOption> options;
|
||||||
|
private String label;
|
||||||
|
private String message;
|
||||||
|
}
|
|
@ -46,7 +46,6 @@ import io.metersphere.request.issues.IssueImportRequest;
|
||||||
import io.metersphere.request.issues.PlatformIssueTypeRequest;
|
import io.metersphere.request.issues.PlatformIssueTypeRequest;
|
||||||
import io.metersphere.request.testcase.AuthUserIssueRequest;
|
import io.metersphere.request.testcase.AuthUserIssueRequest;
|
||||||
import io.metersphere.request.testcase.IssuesCountRequest;
|
import io.metersphere.request.testcase.IssuesCountRequest;
|
||||||
import io.metersphere.service.issue.domain.zentao.ZentaoBuild;
|
|
||||||
import io.metersphere.service.issue.platform.*;
|
import io.metersphere.service.issue.platform.*;
|
||||||
import io.metersphere.service.remote.project.TrackCustomFieldTemplateService;
|
import io.metersphere.service.remote.project.TrackCustomFieldTemplateService;
|
||||||
import io.metersphere.service.remote.project.TrackIssueTemplateService;
|
import io.metersphere.service.remote.project.TrackIssueTemplateService;
|
||||||
|
@ -141,6 +140,8 @@ public class IssuesService {
|
||||||
private PlatformPluginService platformPluginService;
|
private PlatformPluginService platformPluginService;
|
||||||
@Resource
|
@Resource
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
@Resource
|
||||||
|
private BasePluginService basePluginService;
|
||||||
|
|
||||||
private static final String SYNC_THIRD_PARTY_ISSUES_KEY = "ISSUE:SYNC";
|
private static final String SYNC_THIRD_PARTY_ISSUES_KEY = "ISSUE:SYNC";
|
||||||
|
|
||||||
|
@ -481,10 +482,6 @@ public class IssuesService {
|
||||||
List<String> tapdUsers = tapdPlatform.getTapdUsers(issuesWithBLOBs.getProjectId(), issuesWithBLOBs.getPlatformId());
|
List<String> tapdUsers = tapdPlatform.getTapdUsers(issuesWithBLOBs.getProjectId(), issuesWithBLOBs.getPlatformId());
|
||||||
issuesWithBLOBs.setTapdUsers(tapdUsers);
|
issuesWithBLOBs.setTapdUsers(tapdUsers);
|
||||||
}
|
}
|
||||||
if (StringUtils.equals(issuesWithBLOBs.getPlatform(), IssuesManagePlatform.Zentao.name())) {
|
|
||||||
ZentaoPlatform zentaoPlatform = (ZentaoPlatform) IssueFactory.createPlatform(IssuesManagePlatform.Zentao.name(), issuesRequest);
|
|
||||||
zentaoPlatform.getZentaoAssignedAndBuilds(issuesWithBLOBs);
|
|
||||||
}
|
|
||||||
buildCustomField(issuesWithBLOBs);
|
buildCustomField(issuesWithBLOBs);
|
||||||
return issuesWithBLOBs;
|
return issuesWithBLOBs;
|
||||||
}
|
}
|
||||||
|
@ -649,18 +646,6 @@ public class IssuesService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ZentaoBuild> getZentaoBuilds(IssuesRequest request) {
|
|
||||||
try {
|
|
||||||
ZentaoPlatform platform = (ZentaoPlatform) IssueFactory.createPlatform(IssuesManagePlatform.Zentao.name(), request);
|
|
||||||
return platform.getBuilds();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error("get zentao builds fail.");
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(Translator.get("zentao_get_project_builds_fail"));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<IssuesDao> list(IssuesRequest request) {
|
public List<IssuesDao> list(IssuesRequest request) {
|
||||||
request.setOrders(ServiceUtils.getDefaultOrderByField(request.getOrders(), "create_time"));
|
request.setOrders(ServiceUtils.getDefaultOrderByField(request.getOrders(), "create_time"));
|
||||||
request.getOrders().forEach(order -> {
|
request.getOrders().forEach(order -> {
|
||||||
|
@ -1148,6 +1133,8 @@ public class IssuesService {
|
||||||
public String getDefaultCustomFields(String projectId) {
|
public String getDefaultCustomFields(String projectId) {
|
||||||
IssueTemplateDao template = trackIssueTemplateService.getTemplate(projectId);
|
IssueTemplateDao template = trackIssueTemplateService.getTemplate(projectId);
|
||||||
List<CustomFieldDao> customFields = trackCustomFieldTemplateService.getCustomFieldByTemplateId(template.getId());
|
List<CustomFieldDao> customFields = trackCustomFieldTemplateService.getCustomFieldByTemplateId(template.getId());
|
||||||
|
List<CustomFieldDao> pluginCustomFields = getPluginCustomFields(projectId);
|
||||||
|
customFields.addAll(pluginCustomFields);
|
||||||
return getCustomFieldsValuesString(customFields);
|
return getCustomFieldsValuesString(customFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1370,6 +1357,47 @@ public class IssuesService {
|
||||||
return issueTemplateDao;
|
return issueTemplateDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<CustomFieldDao> getPluginCustomFields(String projectId) {
|
||||||
|
List<CustomFieldDao> fields = new ArrayList<>();
|
||||||
|
if (StringUtils.isNotBlank(projectId)) {
|
||||||
|
Project project = baseProjectService.getProjectById(projectId);
|
||||||
|
PluginWithBLOBs plugin = basePluginService.getByScripId(project.getPlatform());
|
||||||
|
if (plugin == null) {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
Map metaData = JSON.parseMap(plugin.getFormScript());
|
||||||
|
Object issueConfig = metaData.get("issueConfig");
|
||||||
|
List<ThirdPartIssueField> thirdPartIssueFields = null;
|
||||||
|
if (issueConfig != null) {
|
||||||
|
String formItems = JSON.toJSONString(((Map) issueConfig).get("formItems"));
|
||||||
|
thirdPartIssueFields = JSON.parseArray(formItems, ThirdPartIssueField.class);
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(thirdPartIssueFields)) {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
char filedKey = 'A';
|
||||||
|
for (ThirdPartIssueField item : thirdPartIssueFields) {
|
||||||
|
CustomFieldDao customField = new CustomFieldDao();
|
||||||
|
BeanUtils.copyBean(customField, item);
|
||||||
|
customField.setKey(String.valueOf(filedKey++));
|
||||||
|
customField.setId(item.getName());
|
||||||
|
customField.setCustomData(item.getName());
|
||||||
|
customField.setName(item.getLabel());
|
||||||
|
if (StringUtils.isNotBlank(item.getOptionMethod())) {
|
||||||
|
Platform platform = platformPluginService.getPlatform(project.getPlatform());
|
||||||
|
GetOptionRequest request = new GetOptionRequest();
|
||||||
|
request.setOptionMethod(item.getOptionMethod());
|
||||||
|
request.setProjectConfig(PlatformPluginService.getCompatibleProjectConfig(project));
|
||||||
|
customField.setOptions(JSON.toJSONString(platform.getFormOptions(request)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fields.add(customField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
public IssuesRequest getDefaultIssueRequest(String projectId, String workspaceId) {
|
public IssuesRequest getDefaultIssueRequest(String projectId, String workspaceId) {
|
||||||
IssuesRequest issuesRequest = new IssuesRequest();
|
IssuesRequest issuesRequest = new IssuesRequest();
|
||||||
issuesRequest.setProjectId(projectId);
|
issuesRequest.setProjectId(projectId);
|
||||||
|
@ -1443,9 +1471,6 @@ public class IssuesService {
|
||||||
if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Tapd.name())) {
|
if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Tapd.name())) {
|
||||||
TapdPlatform tapd = new TapdPlatform(issuesRequest);
|
TapdPlatform tapd = new TapdPlatform(issuesRequest);
|
||||||
this.doCheckThirdProjectExist(tapd, project.getTapdId());
|
this.doCheckThirdProjectExist(tapd, project.getTapdId());
|
||||||
} else if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Zentao.name())) {
|
|
||||||
ZentaoPlatform zentao = new ZentaoPlatform(issuesRequest);
|
|
||||||
this.doCheckThirdProjectExist(zentao, project.getZentaoId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import io.metersphere.commons.constants.PluginScenario;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import io.metersphere.platform.domain.PlatformRequest;
|
import io.metersphere.platform.domain.PlatformRequest;
|
||||||
import io.metersphere.platform.domain.SelectOption;
|
import io.metersphere.platform.domain.SelectOption;
|
||||||
|
|
||||||
import io.metersphere.platform.loader.PlatformPluginManager;
|
import io.metersphere.platform.loader.PlatformPluginManager;
|
||||||
import io.metersphere.request.IntegrationRequest;
|
import io.metersphere.request.IntegrationRequest;
|
||||||
import io.metersphere.utils.PluginManagerUtil;
|
import io.metersphere.utils.PluginManagerUtil;
|
||||||
|
@ -122,8 +123,7 @@ public class PlatformPluginService {
|
||||||
|
|
||||||
public static boolean isPluginPlatform(String platform) {
|
public static boolean isPluginPlatform(String platform) {
|
||||||
if (StringUtils.equalsAnyIgnoreCase(platform,
|
if (StringUtils.equalsAnyIgnoreCase(platform,
|
||||||
IssuesManagePlatform.Tapd.name(), IssuesManagePlatform.AzureDevops.name(),
|
IssuesManagePlatform.Tapd.name(), IssuesManagePlatform.AzureDevops.name(), IssuesManagePlatform.Local.name())) {
|
||||||
IssuesManagePlatform.Zentao.name(), IssuesManagePlatform.Local.name())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,263 +0,0 @@
|
||||||
package io.metersphere.service.issue.client;
|
|
||||||
|
|
||||||
import io.metersphere.commons.exception.MSException;
|
|
||||||
import io.metersphere.commons.utils.JSON;
|
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
|
||||||
import io.metersphere.commons.utils.UnicodeConvertUtils;
|
|
||||||
import io.metersphere.service.issue.domain.zentao.*;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.core.io.FileSystemResource;
|
|
||||||
import org.springframework.http.*;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public abstract class ZentaoClient extends BaseClient {
|
|
||||||
|
|
||||||
protected String ENDPOINT;
|
|
||||||
|
|
||||||
protected String USER_NAME;
|
|
||||||
|
|
||||||
protected String PASSWD;
|
|
||||||
|
|
||||||
public RequestUrl requestUrl;
|
|
||||||
protected String url;
|
|
||||||
|
|
||||||
public ZentaoClient(String url) {
|
|
||||||
ENDPOINT = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String login() {
|
|
||||||
GetUserResponse getUserResponse = new GetUserResponse();
|
|
||||||
String sessionId = "";
|
|
||||||
try {
|
|
||||||
sessionId = getSessionId();
|
|
||||||
String loginUrl = requestUrl.getLogin();
|
|
||||||
MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();
|
|
||||||
paramMap.add("account", USER_NAME);
|
|
||||||
paramMap.add("password", PASSWD);
|
|
||||||
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(paramMap, new HttpHeaders());
|
|
||||||
ResponseEntity<String> response = restTemplate.exchange(loginUrl + sessionId, HttpMethod.POST, requestEntity, String.class);
|
|
||||||
getUserResponse = (GetUserResponse) getResultForObject(GetUserResponse.class, response);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
GetUserResponse.User user = getUserResponse.getUser();
|
|
||||||
if (user == null) {
|
|
||||||
LogUtil.error(JSON.toJSONString(getUserResponse));
|
|
||||||
// 登录失败,获取的session无效,置空session
|
|
||||||
MSException.throwException("zentao login fail, user null");
|
|
||||||
}
|
|
||||||
if (!StringUtils.equals(user.getAccount(), USER_NAME)) {
|
|
||||||
LogUtil.error("login fail,inconsistent users");
|
|
||||||
MSException.throwException("zentao login fail, inconsistent user");
|
|
||||||
}
|
|
||||||
return sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSessionId() {
|
|
||||||
String getSessionUrl = requestUrl.getSessionGet();
|
|
||||||
ResponseEntity<String> response = restTemplate.exchange(getSessionUrl,
|
|
||||||
HttpMethod.GET, null, String.class);
|
|
||||||
GetSessionResponse getSessionResponse = (GetSessionResponse) getResultForObject(GetSessionResponse.class, response);
|
|
||||||
return JSON.parseObject(getSessionResponse.getData(), GetSessionResponse.Session.class).getSessionID();
|
|
||||||
}
|
|
||||||
|
|
||||||
public AddIssueResponse.Issue addIssue(MultiValueMap<String, Object> paramMap) {
|
|
||||||
String sessionId = login();
|
|
||||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(paramMap, new HttpHeaders());
|
|
||||||
ResponseEntity<String> response = null;
|
|
||||||
try {
|
|
||||||
String bugCreate = requestUrl.getBugCreate();
|
|
||||||
response = restTemplate.exchange(bugCreate + sessionId,
|
|
||||||
HttpMethod.POST, requestEntity, String.class);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
AddIssueResponse addIssueResponse = (AddIssueResponse) getResultForObject(AddIssueResponse.class, response);
|
|
||||||
AddIssueResponse.Issue issue = JSON.parseObject(addIssueResponse.getData(), AddIssueResponse.Issue.class);
|
|
||||||
if (issue == null) {
|
|
||||||
MSException.throwException(UnicodeConvertUtils.unicodeToCn(response.getBody()));
|
|
||||||
}
|
|
||||||
return issue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateIssue(String id, MultiValueMap<String, Object> paramMap) {
|
|
||||||
String sessionId = login();
|
|
||||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(paramMap, new HttpHeaders());
|
|
||||||
try {
|
|
||||||
restTemplate.exchange(requestUrl.getBugUpdate(),
|
|
||||||
HttpMethod.POST, requestEntity, String.class, id, sessionId);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteIssue(String id) {
|
|
||||||
String sessionId = login();
|
|
||||||
try {
|
|
||||||
restTemplate.exchange(requestUrl.getBugDelete(),
|
|
||||||
HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), String.class, id, sessionId);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
MSException.throwException(e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map getBugById(String id) {
|
|
||||||
String sessionId = login();
|
|
||||||
String bugGet = requestUrl.getBugGet();
|
|
||||||
ResponseEntity<String> response = restTemplate.exchange(bugGet,
|
|
||||||
HttpMethod.GET, null, String.class, id, sessionId);
|
|
||||||
GetIssueResponse getIssueResponse = (GetIssueResponse) getResultForObject(GetIssueResponse.class, response);
|
|
||||||
if(StringUtils.equalsIgnoreCase(getIssueResponse.getStatus(),"fail")){
|
|
||||||
GetIssueResponse.Issue issue = new GetIssueResponse.Issue();
|
|
||||||
issue.setId(id);
|
|
||||||
issue.setSteps(StringUtils.SPACE);
|
|
||||||
issue.setTitle(StringUtils.SPACE);
|
|
||||||
issue.setStatus("closed");
|
|
||||||
issue.setDeleted("1");
|
|
||||||
issue.setOpenedBy(StringUtils.SPACE);
|
|
||||||
getIssueResponse.setData(JSON.toJSONString(issue).toString());
|
|
||||||
}
|
|
||||||
return JSON.parseMap(getIssueResponse.getData());
|
|
||||||
}
|
|
||||||
|
|
||||||
public GetCreateMetaDataResponse.MetaData getCreateMetaData(String productID) {
|
|
||||||
String sessionId = login();
|
|
||||||
ResponseEntity<String> response = restTemplate.exchange(requestUrl.getCreateMetaData(),
|
|
||||||
HttpMethod.GET, null, String.class, productID, sessionId);
|
|
||||||
GetCreateMetaDataResponse getCreateMetaDataResponse = (GetCreateMetaDataResponse) getResultForObject(GetCreateMetaDataResponse.class, response);
|
|
||||||
return JSON.parseObject(getCreateMetaDataResponse.getData(), GetCreateMetaDataResponse.MetaData.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map getCustomFields(String productID) {
|
|
||||||
return getCreateMetaData(productID).getCustomFields();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> getBuildsByCreateMetaData(String projectId) {
|
|
||||||
return getCreateMetaData(projectId).getBuilds();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, Object> getBuilds(String projectId) {
|
|
||||||
String sessionId = login();
|
|
||||||
ResponseEntity<String> response = restTemplate.exchange(requestUrl.getBuildsGet(),
|
|
||||||
HttpMethod.GET, null, String.class, projectId, sessionId);
|
|
||||||
return (Map<String, Object>) JSON.parseMap(response.getBody()).get("data");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map getBugsByProjectId(String projectId, Integer pageNum, Integer pageSize) {
|
|
||||||
String sessionId = login();
|
|
||||||
ResponseEntity<String> response = restTemplate.exchange(requestUrl.getBugList(),
|
|
||||||
HttpMethod.GET, null, String.class, projectId, 9999999, pageSize, pageNum, sessionId);
|
|
||||||
try {
|
|
||||||
return JSON.parseMap(JSON.parseMap(response.getBody()).get("data").toString());
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e);
|
|
||||||
MSException.throwException("请检查配置信息是否填写正确!");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBaseUrl() {
|
|
||||||
if (ENDPOINT.endsWith("/")) {
|
|
||||||
return ENDPOINT.substring(0, ENDPOINT.length() - 1);
|
|
||||||
}
|
|
||||||
return ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConfig(ZentaoConfig config) {
|
|
||||||
if (config == null) {
|
|
||||||
MSException.throwException("config is null");
|
|
||||||
}
|
|
||||||
USER_NAME = config.getAccount();
|
|
||||||
PASSWD = config.getPassword();
|
|
||||||
ENDPOINT = config.getUrl();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public String getReplaceImgUrl(String replaceImgUrl) {
|
|
||||||
String baseUrl = getBaseUrl();
|
|
||||||
String[] split = baseUrl.split("/");
|
|
||||||
String suffix = split[split.length - 1];
|
|
||||||
if (StringUtils.equals("biz", suffix)) {
|
|
||||||
suffix = baseUrl;
|
|
||||||
} else if (!StringUtils.equalsAny(suffix, "zentao", "pro", "zentaopms", "zentaopro", "zentaobiz")) {
|
|
||||||
suffix = "";
|
|
||||||
} else {
|
|
||||||
suffix = "/" + suffix;
|
|
||||||
}
|
|
||||||
return String.format(replaceImgUrl, suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkProjectExist(String relateId) {
|
|
||||||
String sessionId = login();
|
|
||||||
ResponseEntity<String> response = restTemplate.exchange(requestUrl.getProductGet(),
|
|
||||||
HttpMethod.GET, null, String.class, relateId, sessionId);
|
|
||||||
try {
|
|
||||||
Object data = JSON.parseMap(response.getBody()).get("data");
|
|
||||||
if (!StringUtils.equals((String) data, "false")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error("checkProjectExist error: " + response.getBody());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void uploadAttachment(String objectType, String objectId, File file) {
|
|
||||||
String sessionId = login();
|
|
||||||
HttpHeaders authHeader = new HttpHeaders();
|
|
||||||
authHeader.setContentType(MediaType.parseMediaType("multipart/form-data; charset=UTF-8"));
|
|
||||||
|
|
||||||
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
|
||||||
FileSystemResource fileResource = new FileSystemResource(file);
|
|
||||||
paramMap.add("files", fileResource);
|
|
||||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(paramMap, authHeader);
|
|
||||||
|
|
||||||
try {
|
|
||||||
restTemplate.exchange(requestUrl.getFileUpload(), HttpMethod.POST, requestEntity,
|
|
||||||
String.class, objectId, sessionId);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.info("upload zentao attachment error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void deleteAttachment(String fileId) {
|
|
||||||
String sessionId = login();
|
|
||||||
try {
|
|
||||||
restTemplate.exchange(requestUrl.getFileDelete(), HttpMethod.GET, null, String.class, fileId, sessionId);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.info("delete zentao attachment error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getAttachmentBytes(String fileId) {
|
|
||||||
String sessionId = login();
|
|
||||||
ResponseEntity<byte[]> response = restTemplate.exchange(requestUrl.getFileDownload(), HttpMethod.GET,
|
|
||||||
null, byte[].class, fileId, sessionId);
|
|
||||||
return response.getBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResponseEntity proxyForGet(String path, Class responseEntityClazz) {
|
|
||||||
im.metersphere.plugin.utils.LogUtil.info("zentao proxyForGet: " + path);
|
|
||||||
String url = this.ENDPOINT + path;
|
|
||||||
try {
|
|
||||||
if (!StringUtils.containsAny(new URI(url).getPath(), "/index.php", "/file-read-")) {
|
|
||||||
// 只允许访问图片
|
|
||||||
MSException.throwException("illegal path");
|
|
||||||
}
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
LogUtil.error(e);
|
|
||||||
MSException.throwException("illegal path");
|
|
||||||
}
|
|
||||||
return restTemplate.exchange(url, HttpMethod.GET, null, responseEntityClazz);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
package io.metersphere.service.issue.client;
|
|
||||||
|
|
||||||
|
|
||||||
import io.metersphere.service.issue.domain.zentao.RequestUrl;
|
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class ZentaoGetClient extends ZentaoClient {
|
|
||||||
|
|
||||||
private static final String LOGIN = "/?m=user&f=login&t=json&zentaosid=";
|
|
||||||
private static final String SESSION_GET="/?m=api&f=getSessionID&t=json";
|
|
||||||
private static final String BUG_CREATE="&module=bug&methodName=create&t=json&zentaosid=";
|
|
||||||
private static final String BUG_UPDATE = "&module=bug&methodName=update¶ms=bugID={0}&t=json&zentaosid={1}";
|
|
||||||
private static final String BUG_DELETE = "/?m=bug&f=delete&bugID={0}&confirm=yes&t=json&zentaosid={1}";
|
|
||||||
private static final String BUG_GET="&module=bug&methodName=getById¶ms=bugID={1}&t=json&zentaosid={2}";
|
|
||||||
private static final String STORY_GET="&module=story&methodName=getProductStories¶ms=productID={key}&t=json&zentaosid=";
|
|
||||||
private static final String USER_GET="&module=user&methodName=getList&t=json&zentaosid=";
|
|
||||||
private static final String BUILDS_GET="&module=build&methodName=getProductBuildPairs&productID={0}&zentaosid={1}";
|
|
||||||
private static final String FILE_UPLOAD="&module=file&methodName=saveUpload¶ms=objectType=bug,objectID={1}&zentaosid={2}";
|
|
||||||
private static final String FILE_DELETE="/?m=file&f=delete&t=json&fileID={1}&confirm=yes&zentaosid={2}";
|
|
||||||
private static final String FILE_DOWNLOAD="/?m=file&f=download&t=json&fileID={1}&mouse=click&zentaosid={2}";
|
|
||||||
private static final String CREATE_META_DATA="?m=bug&f=create&productID={0}&t=json&zentaosid={1}";
|
|
||||||
private static final String REPLACE_IMG_URL="<img src=\"%s/index.php?m=file&f=read&fileID=$1\"/>";
|
|
||||||
private static final Pattern IMG_PATTERN = Pattern.compile("m=file&f=read&fileID=(.*?)\"/>");
|
|
||||||
private static final String PRODUCT_GET = "&module=product&methodName=getById¶ms=productID={0}&zentaosid={1}";
|
|
||||||
/**
|
|
||||||
* 注意 recTotal={1}&recPerPage={2}&pageID={3} 顺序不能调换,有点恶心
|
|
||||||
*/
|
|
||||||
private static final String BUG_LIST_URL = "/?m=bug&f=browse&productID={0}&branch=&browseType=all¶m=0&orderBy=&recTotal={1}&recPerPage={2}&pageID={3}&t=json&zentaosid={4}";
|
|
||||||
|
|
||||||
RequestUrl request = new RequestUrl();
|
|
||||||
|
|
||||||
public ZentaoGetClient(String url) {
|
|
||||||
super(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
request.setLogin(getNotSuperModelUrl(LOGIN));
|
|
||||||
request.setSessionGet(getNotSuperModelUrl(SESSION_GET));
|
|
||||||
request.setBugCreate(getUrl(BUG_CREATE));
|
|
||||||
request.setBugGet(getUrl(BUG_GET));
|
|
||||||
request.setStoryGet(getUrl(STORY_GET));
|
|
||||||
request.setUserGet(getUrl(USER_GET));
|
|
||||||
request.setBuildsGet(getUrl(BUILDS_GET));
|
|
||||||
request.setFileUpload(getUrl(FILE_UPLOAD));
|
|
||||||
request.setReplaceImgUrl(getReplaceImgUrl(REPLACE_IMG_URL));
|
|
||||||
request.setImgPattern(IMG_PATTERN);
|
|
||||||
request.setBugUpdate(getUrl(BUG_UPDATE));
|
|
||||||
request.setBugDelete(getNotSuperModelUrl(BUG_DELETE));
|
|
||||||
request.setBugList(getNotSuperModelUrl(BUG_LIST_URL));
|
|
||||||
request.setCreateMetaData(getNotSuperModelUrl(CREATE_META_DATA));
|
|
||||||
request.setProductGet(getUrl(PRODUCT_GET));
|
|
||||||
request.setFileDelete(getNotSuperModelUrl(FILE_DELETE));
|
|
||||||
request.setFileDownload(getNotSuperModelUrl(FILE_DOWNLOAD));
|
|
||||||
requestUrl = request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getUrl(String url) {
|
|
||||||
return getBaseUrl() + "/?m=api&f=getModel" + url;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getNotSuperModelUrl(String url) {
|
|
||||||
return getBaseUrl() + url;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
package io.metersphere.service.issue.client;
|
|
||||||
|
|
||||||
import io.metersphere.service.issue.domain.zentao.RequestUrl;
|
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class ZentaoPathInfoClient extends ZentaoClient {
|
|
||||||
|
|
||||||
private static final String LOGIN = "/user-login.json?zentaosid=";
|
|
||||||
private static final String SESSION_GET = "/api-getsessionid.json";
|
|
||||||
private static final String BUG_CREATE = "/api-getModel-bug-create.json?zentaosid=";
|
|
||||||
private static final String BUG_UPDATE = "/api-getModel-bug-update-bugID={1}.json?zentaosid={2}";
|
|
||||||
private static final String BUG_DELETE = "/bug-delete-{1}-yes.json?zentaosid={2}";
|
|
||||||
private static final String BUG_GET = "/api-getModel-bug-getById-bugID={1}?zentaosid={2}";
|
|
||||||
private static final String STORY_GET = "/api-getModel-story-getProductStories-productID={key}?zentaosid=";
|
|
||||||
private static final String USER_GET = "/api-getModel-user-getList?zentaosid=";
|
|
||||||
private static final String BUILDS_GET = "/api-getModel-build-getProductBuildPairs-productID={0}?zentaosid={1}";
|
|
||||||
private static final String CREATE_META_DATA="/bug-create-{0}.json?zentaosid={1}";
|
|
||||||
private static final String FILE_UPLOAD = "/api-getModel-file-saveUpload-objectType=bug,objectID={1}?zentaosid={2}";
|
|
||||||
private static final String FILE_DELETE = "/file-delete-{1}-.yes.json?zentaosid={2}";
|
|
||||||
private static final String FILE_DOWNLOAD="/file-download-{1}-.click.json?zentaosid={2}";
|
|
||||||
private static final String REPLACE_IMG_URL = "<img src=\"%s/file-read-$1\"/>";
|
|
||||||
private static final Pattern IMG_PATTERN = Pattern.compile("file-read-(.*?)\"/>");
|
|
||||||
private static final String PRODUCT_GET = "/api-getModel-product-getById-productID={0}?zentaosid={1}";
|
|
||||||
private static final String BUG_LIST_URL = "/bug-browse-{1}-0-all-0--{2}-{3}-{4}.json?&zentaosid={5}";
|
|
||||||
|
|
||||||
public ZentaoPathInfoClient(String url) {
|
|
||||||
super(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected RequestUrl request = new RequestUrl();
|
|
||||||
|
|
||||||
{
|
|
||||||
request.setLogin(getUrl(LOGIN));
|
|
||||||
request.setSessionGet(getUrl(SESSION_GET));
|
|
||||||
request.setBugCreate(getUrl(BUG_CREATE));
|
|
||||||
request.setBugGet(getUrl(BUG_GET));
|
|
||||||
request.setStoryGet(getUrl(STORY_GET));
|
|
||||||
request.setUserGet(getUrl(USER_GET));
|
|
||||||
request.setBuildsGet(getUrl(BUILDS_GET));
|
|
||||||
request.setFileUpload(getUrl(FILE_UPLOAD));
|
|
||||||
request.setReplaceImgUrl(getReplaceImgUrl(REPLACE_IMG_URL));
|
|
||||||
request.setImgPattern(IMG_PATTERN);
|
|
||||||
request.setBugUpdate(getUrl(BUG_UPDATE));
|
|
||||||
request.setBugDelete(getUrl(BUG_DELETE));
|
|
||||||
request.setBugList(getUrl(BUG_LIST_URL));
|
|
||||||
request.setCreateMetaData(getUrl(CREATE_META_DATA));
|
|
||||||
request.setProductGet(getUrl(PRODUCT_GET));
|
|
||||||
request.setFileDelete(getUrl(FILE_DELETE));
|
|
||||||
request.setFileDownload(getUrl(FILE_DOWNLOAD));
|
|
||||||
requestUrl = request;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getUrl(String url) {
|
|
||||||
return getBaseUrl() + url;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.zentao;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class AddIssueResponse extends ZentaoResponse {
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public static class Issue {
|
|
||||||
private String status;
|
|
||||||
private String id;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.zentao;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class GetCreateMetaDataResponse extends ZentaoResponse {
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public static class MetaData {
|
|
||||||
private String title;
|
|
||||||
private Map users;
|
|
||||||
private Map customFields;
|
|
||||||
private Map<String, Object> builds;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.zentao;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class GetIssueResponse extends ZentaoResponse {
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public static class Issue {
|
|
||||||
private String id;
|
|
||||||
private String title;
|
|
||||||
private String steps;
|
|
||||||
private String status;
|
|
||||||
private String openedBy;
|
|
||||||
// private String openedDate;
|
|
||||||
private String deleted;
|
|
||||||
// private String product;
|
|
||||||
// private String openedBuild;
|
|
||||||
// private String assignedTo;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.zentao;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class GetSessionResponse extends ZentaoResponse {
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public static class Session {
|
|
||||||
// private String title;
|
|
||||||
// private String sessionName;
|
|
||||||
private String sessionID;
|
|
||||||
// private int rand;
|
|
||||||
// private String pager;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.zentao;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class GetUserResponse {
|
|
||||||
private String status;
|
|
||||||
private User user;
|
|
||||||
private String reason;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public static class User {
|
|
||||||
private String id;
|
|
||||||
private String account;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.zentao;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class RequestUrl {
|
|
||||||
private String login;
|
|
||||||
private String sessionGet;
|
|
||||||
private String bugCreate;
|
|
||||||
private String createMetaData;
|
|
||||||
private String bugUpdate;
|
|
||||||
private String bugList;
|
|
||||||
private String bugDelete;
|
|
||||||
private String bugGet;
|
|
||||||
private String storyGet;
|
|
||||||
private String userGet;
|
|
||||||
private String buildsGet;
|
|
||||||
private String fileUpload;
|
|
||||||
private String fileDelete;
|
|
||||||
private String fileDownload;
|
|
||||||
private String replaceImgUrl;
|
|
||||||
private String productGet;
|
|
||||||
private Pattern imgPattern;
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.zentao;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class ZentaoBuild {
|
|
||||||
private String id;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
public ZentaoBuild(String id, String name) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZentaoBuild() {}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.zentao;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class ZentaoConfig {
|
|
||||||
private String account;
|
|
||||||
private String password;
|
|
||||||
private String url;
|
|
||||||
private String requestType;
|
|
||||||
private String request;
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package io.metersphere.service.issue.domain.zentao;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
public class ZentaoResponse {
|
|
||||||
private String status;
|
|
||||||
private String md5;
|
|
||||||
private String data;
|
|
||||||
}
|
|
|
@ -16,8 +16,6 @@ public class IssueFactory {
|
||||||
public static IssuesPlatform createPlatform(String platform, IssuesRequest addIssueRequest) {
|
public static IssuesPlatform createPlatform(String platform, IssuesRequest addIssueRequest) {
|
||||||
if (StringUtils.equals(IssuesManagePlatform.Tapd.toString(), platform)) {
|
if (StringUtils.equals(IssuesManagePlatform.Tapd.toString(), platform)) {
|
||||||
return new TapdPlatform(addIssueRequest);
|
return new TapdPlatform(addIssueRequest);
|
||||||
} else if (StringUtils.equals(IssuesManagePlatform.Zentao.toString(), platform)) {
|
|
||||||
return new ZentaoPlatform(addIssueRequest);
|
|
||||||
} else if (StringUtils.equals(IssuesManagePlatform.AzureDevops.toString(), platform)) {
|
} else if (StringUtils.equals(IssuesManagePlatform.AzureDevops.toString(), platform)) {
|
||||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
package io.metersphere.service.issue.platform;
|
|
||||||
|
|
||||||
import io.metersphere.service.issue.client.ZentaoClient;
|
|
||||||
import io.metersphere.service.issue.client.ZentaoGetClient;
|
|
||||||
import io.metersphere.service.issue.client.ZentaoPathInfoClient;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
public class ZentaoFactory {
|
|
||||||
|
|
||||||
public static ZentaoClient getInstance(String url, String type) {
|
|
||||||
if (StringUtils.equals(type, "PATH_INFO")) {
|
|
||||||
return new ZentaoPathInfoClient(url);
|
|
||||||
} else if (StringUtils.equals(type, "GET")) {
|
|
||||||
return new ZentaoGetClient(url);
|
|
||||||
}
|
|
||||||
return new ZentaoPathInfoClient(url);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,692 +0,0 @@
|
||||||
package io.metersphere.service.issue.platform;
|
|
||||||
|
|
||||||
import io.metersphere.base.domain.*;
|
|
||||||
import io.metersphere.commons.constants.IssuesManagePlatform;
|
|
||||||
import io.metersphere.commons.constants.IssuesStatus;
|
|
||||||
import io.metersphere.commons.constants.ZentaoIssuePlatformStatus;
|
|
||||||
import io.metersphere.commons.exception.MSException;
|
|
||||||
import io.metersphere.commons.utils.DateUtils;
|
|
||||||
import io.metersphere.commons.utils.JSON;
|
|
||||||
import io.metersphere.commons.utils.LogUtil;
|
|
||||||
import io.metersphere.xpack.track.dto.AttachmentSyncType;
|
|
||||||
import io.metersphere.constants.AttachmentType;
|
|
||||||
import io.metersphere.dto.*;
|
|
||||||
import io.metersphere.xpack.track.dto.AttachmentRequest;
|
|
||||||
import io.metersphere.xpack.track.dto.DemandDTO;
|
|
||||||
import io.metersphere.xpack.track.dto.IssuesDao;
|
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
|
||||||
import io.metersphere.service.issue.client.ZentaoClient;
|
|
||||||
import io.metersphere.service.issue.client.ZentaoGetClient;
|
|
||||||
import io.metersphere.xpack.track.dto.PlatformUser;
|
|
||||||
|
|
||||||
import io.metersphere.service.issue.domain.zentao.AddIssueResponse;
|
|
||||||
import io.metersphere.service.issue.domain.zentao.GetIssueResponse;
|
|
||||||
import io.metersphere.service.issue.domain.zentao.ZentaoBuild;
|
|
||||||
import io.metersphere.service.issue.domain.zentao.ZentaoConfig;
|
|
||||||
import io.metersphere.xpack.track.dto.PlatformStatusDTO;
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.logging.log4j.util.Strings;
|
|
||||||
import org.springframework.core.io.FileSystemResource;
|
|
||||||
import org.springframework.http.HttpEntity;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class ZentaoPlatform extends AbstractIssuePlatform {
|
|
||||||
protected final ZentaoClient zentaoClient;
|
|
||||||
|
|
||||||
protected final String[] imgArray = {
|
|
||||||
"bmp", "jpg", "png", "tif", "gif", "jpeg"
|
|
||||||
};
|
|
||||||
|
|
||||||
// xpack 反射调用
|
|
||||||
public ZentaoClient getZentaoClient() {
|
|
||||||
return zentaoClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZentaoPlatform(IssuesRequest issuesRequest) {
|
|
||||||
super(issuesRequest);
|
|
||||||
this.key = IssuesManagePlatform.Zentao.name();
|
|
||||||
ZentaoConfig zentaoConfig = getConfig();
|
|
||||||
this.workspaceId = issuesRequest.getWorkspaceId();
|
|
||||||
this.zentaoClient = ZentaoFactory.getInstance(zentaoConfig.getUrl(), zentaoConfig.getRequest());
|
|
||||||
this.zentaoClient.setConfig(zentaoConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getProjectId(String projectId) {
|
|
||||||
return getProjectId(projectId, Project::getZentaoId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<IssuesDao> getIssue(IssuesRequest issuesRequest) {
|
|
||||||
issuesRequest.setPlatform(key);
|
|
||||||
List<IssuesDao> issues;
|
|
||||||
if (StringUtils.isNotBlank(issuesRequest.getProjectId())) {
|
|
||||||
issues = extIssuesMapper.getIssues(issuesRequest);
|
|
||||||
} else {
|
|
||||||
issues = extIssuesMapper.getIssuesByCaseId(issuesRequest);
|
|
||||||
}
|
|
||||||
return issues;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IssuesDao getZentaoAssignedAndBuilds(IssuesDao issue) {
|
|
||||||
Map zentaoIssue = (Map) zentaoClient.getBugById(issue.getPlatformId());
|
|
||||||
String assignedTo = zentaoIssue.get("assignedTo").toString();
|
|
||||||
String openedBuild = zentaoIssue.get("openedBuild").toString();
|
|
||||||
List<String> zentaoBuilds = new ArrayList<>();
|
|
||||||
if (Strings.isNotBlank(openedBuild)) {
|
|
||||||
zentaoBuilds = Arrays.asList(openedBuild.split(","));
|
|
||||||
}
|
|
||||||
issue.setZentaoAssigned(assignedTo);
|
|
||||||
issue.setZentaoBuilds(zentaoBuilds);
|
|
||||||
return issue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<DemandDTO> getDemandList(String projectId) {
|
|
||||||
//getTestStories
|
|
||||||
List<DemandDTO> list = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
String session = zentaoClient.login();
|
|
||||||
String key = getProjectId(projectId);
|
|
||||||
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(new HttpHeaders());
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
|
||||||
String storyGet = zentaoClient.requestUrl.getStoryGet();
|
|
||||||
ResponseEntity<String> responseEntity = restTemplate.exchange(storyGet + session,
|
|
||||||
HttpMethod.POST, requestEntity, String.class, key);
|
|
||||||
String body = responseEntity.getBody();
|
|
||||||
Map obj = JSON.parseMap(body);
|
|
||||||
|
|
||||||
LogUtil.info("project story: " + key + obj);
|
|
||||||
|
|
||||||
if (obj != null) {
|
|
||||||
String data = obj.get("data").toString();
|
|
||||||
if (StringUtils.isBlank(data)) {
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
// 兼容处理11.5版本格式 [{obj},{obj}]
|
|
||||||
if (data.charAt(0) == '[') {
|
|
||||||
List array = (List) obj.get("data");
|
|
||||||
for (int i = 0; i < array.size(); i++) {
|
|
||||||
Map o = (Map) array.get(i);
|
|
||||||
DemandDTO demandDTO = new DemandDTO();
|
|
||||||
demandDTO.setId(o.get("id").toString());
|
|
||||||
demandDTO.setName(o.get("title").toString());
|
|
||||||
demandDTO.setPlatform(key);
|
|
||||||
list.add(demandDTO);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// {"5": {"children": {"51": {}}}, "6": {}}
|
|
||||||
else if (data.startsWith("{\"")) {
|
|
||||||
Map<String, Map<String, String>> dataMap = JSON.parseMap(data);
|
|
||||||
Collection<Map<String, String>> values = dataMap.values();
|
|
||||||
values.forEach(v -> {
|
|
||||||
Map jsonObject = JSON.parseMap(JSON.toJSONString(v));
|
|
||||||
DemandDTO demandDTO = new DemandDTO();
|
|
||||||
demandDTO.setId(jsonObject.get("id").toString());
|
|
||||||
demandDTO.setName(jsonObject.get("title").toString());
|
|
||||||
demandDTO.setPlatform(key);
|
|
||||||
list.add(demandDTO);
|
|
||||||
if (jsonObject.get("children") != null) {
|
|
||||||
LinkedHashMap<String, Map<String, String>> children = (LinkedHashMap<String, Map<String, String>>) jsonObject.get("children");
|
|
||||||
Collection<Map<String, String>> childrenMap = children.values();
|
|
||||||
childrenMap.forEach(ch -> {
|
|
||||||
DemandDTO dto = new DemandDTO();
|
|
||||||
dto.setId(ch.get("id"));
|
|
||||||
dto.setName(ch.get("title"));
|
|
||||||
dto.setPlatform(key);
|
|
||||||
list.add(dto);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 处理格式 {{"id": {obj}},{"id",{obj}}}
|
|
||||||
else if (data.charAt(0) == '{') {
|
|
||||||
Map dataObject = (Map) obj.get("data");
|
|
||||||
String s = JSON.toJSONString(dataObject);
|
|
||||||
Map<String, Object> map = JSON.parseMap(s);
|
|
||||||
Collection<Object> values = map.values();
|
|
||||||
values.forEach(v -> {
|
|
||||||
Map jsonObject = JSON.parseMap(JSON.toJSONString(v));
|
|
||||||
DemandDTO demandDTO = new DemandDTO();
|
|
||||||
demandDTO.setId(jsonObject.get("id").toString());
|
|
||||||
demandDTO.setName(jsonObject.get("title").toString());
|
|
||||||
demandDTO.setPlatform(key);
|
|
||||||
list.add(demandDTO);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error("get zentao demand fail " + e.getMessage());
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IssuesWithBLOBs getUpdateIssues(Map bug) {
|
|
||||||
return getUpdateIssues(null, bug);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新缺陷数据
|
|
||||||
*
|
|
||||||
* @param issue 待更新缺陷数据
|
|
||||||
* @param bug 平台缺陷数据
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public IssuesWithBLOBs getUpdateIssues(IssuesWithBLOBs issue, Map bug) {
|
|
||||||
|
|
||||||
GetIssueResponse.Issue bugObj = JSON.parseObject(JSON.toJSONString(bug), GetIssueResponse.Issue.class);
|
|
||||||
String description = bugObj.getSteps();
|
|
||||||
String steps = description;
|
|
||||||
try {
|
|
||||||
steps = htmlDesc2MsDesc(zentao2MsDescription(description));
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
if (issue == null) {
|
|
||||||
issue = new IssuesWithBLOBs();
|
|
||||||
issue.setCustomFields(defaultCustomFields);
|
|
||||||
} else {
|
|
||||||
mergeCustomField(issue, defaultCustomFields);
|
|
||||||
}
|
|
||||||
issue.setPlatformStatus(bugObj.getStatus());
|
|
||||||
if (StringUtils.equals(bugObj.getDeleted(), "1")) {
|
|
||||||
issue.setPlatformStatus(IssuesStatus.DELETE.toString());
|
|
||||||
issuesMapper.updateByPrimaryKeySelective(issue);
|
|
||||||
}
|
|
||||||
issue.setTitle(bugObj.getTitle());
|
|
||||||
issue.setDescription(steps);
|
|
||||||
issue.setReporter(bugObj.getOpenedBy());
|
|
||||||
issue.setPlatform(key);
|
|
||||||
try {
|
|
||||||
String openedDate = bug.get("openedDate").toString();
|
|
||||||
String lastEditedDate = bug.get("lastEditedDate").toString();
|
|
||||||
if (StringUtils.isNotBlank(openedDate) && !openedDate.startsWith("0000-00-00"))
|
|
||||||
issue.setCreateTime(DateUtils.getTime(openedDate).getTime());
|
|
||||||
if (StringUtils.isNotBlank(lastEditedDate) && !lastEditedDate.startsWith("0000-00-00"))
|
|
||||||
issue.setUpdateTime(DateUtils.getTime(lastEditedDate).getTime());
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error("update zentao time" + e.getMessage());
|
|
||||||
}
|
|
||||||
if (issue.getUpdateTime() == null) {
|
|
||||||
issue.setUpdateTime(System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
issue.setCustomFields(syncIssueCustomField(issue.getCustomFields(), bug));
|
|
||||||
return issue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IssuesWithBLOBs addIssue(IssuesUpdateRequest issuesRequest) {
|
|
||||||
setUserConfig();
|
|
||||||
|
|
||||||
MultiValueMap<String, Object> param = buildUpdateParam(issuesRequest);
|
|
||||||
AddIssueResponse.Issue issue = zentaoClient.addIssue(param);
|
|
||||||
issuesRequest.setPlatformStatus(issue.getStatus());
|
|
||||||
|
|
||||||
IssuesWithBLOBs issues = null;
|
|
||||||
|
|
||||||
String id = issue.getId();
|
|
||||||
if (StringUtils.isNotBlank(id)) {
|
|
||||||
issuesRequest.setPlatformId(id);
|
|
||||||
issuesRequest.setId(UUID.randomUUID().toString());
|
|
||||||
|
|
||||||
IssuesExample issuesExample = new IssuesExample();
|
|
||||||
issuesExample.createCriteria().andIdEqualTo(id)
|
|
||||||
.andPlatformEqualTo(key);
|
|
||||||
if (issuesMapper.selectByExample(issuesExample).size() <= 0) {
|
|
||||||
// 插入缺陷表
|
|
||||||
issues = insertIssues(issuesRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 用例与第三方缺陷平台中的缺陷关联
|
|
||||||
handleTestCaseIssues(issuesRequest);
|
|
||||||
} else {
|
|
||||||
MSException.throwException("请确认该Zentao账号是否开启超级model调用接口权限");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果是复制新增, 同步MS附件到Zentao
|
|
||||||
if (StringUtils.isNotEmpty(issuesRequest.getCopyIssueId())) {
|
|
||||||
AttachmentRequest request = new AttachmentRequest();
|
|
||||||
request.setBelongId(issuesRequest.getCopyIssueId());
|
|
||||||
request.setBelongType(AttachmentType.ISSUE.type());
|
|
||||||
List<String> attachmentIds = attachmentService.getAttachmentIdsByParam(request);
|
|
||||||
if (CollectionUtils.isNotEmpty(attachmentIds)) {
|
|
||||||
attachmentIds.forEach(attachmentId -> {
|
|
||||||
FileAttachmentMetadata fileAttachmentMetadata = attachmentService.getFileAttachmentMetadataByFileId(attachmentId);
|
|
||||||
File file = new File(fileAttachmentMetadata.getFilePath() + File.separator + fileAttachmentMetadata.getName());
|
|
||||||
zentaoClient.uploadAttachment("bug", issuesRequest.getPlatformId(), file);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return issues;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateIssue(IssuesUpdateRequest request) {
|
|
||||||
setUserConfig();
|
|
||||||
MultiValueMap<String, Object> param = buildUpdateParam(request);
|
|
||||||
if (request.getTransitions() != null) {
|
|
||||||
request.setPlatformStatus(request.getTransitions().getValue());
|
|
||||||
}
|
|
||||||
handleIssueUpdate(request);
|
|
||||||
this.handleZentaoBugStatus(param);
|
|
||||||
zentaoClient.updateIssue(request.getPlatformId(), param);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleZentaoBugStatus(MultiValueMap<String, Object> param) {
|
|
||||||
if (!param.containsKey("status")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<Object> status = param.get("status");
|
|
||||||
if (CollectionUtils.isEmpty(status)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
||||||
String str = (String) status.get(0);
|
|
||||||
if (StringUtils.equals(str, "resolved")) {
|
|
||||||
param.add("resolvedDate", format.format(new Date()));
|
|
||||||
} else if (StringUtils.equals(str, "closed")) {
|
|
||||||
param.add("closedDate", format.format(new Date()));
|
|
||||||
if (!param.containsKey("resolution")) {
|
|
||||||
// 解决方案默认为已解决
|
|
||||||
param.add("resolution", "fixed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private MultiValueMap<String, Object> buildUpdateParam(IssuesUpdateRequest issuesRequest) {
|
|
||||||
issuesRequest.setPlatform(key);
|
|
||||||
String projectId = getProjectId(issuesRequest.getProjectId());
|
|
||||||
if (StringUtils.isBlank(projectId)) {
|
|
||||||
MSException.throwException("未关联禅道项目ID.");
|
|
||||||
}
|
|
||||||
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
|
||||||
paramMap.add("product", projectId);
|
|
||||||
paramMap.add("title", issuesRequest.getTitle());
|
|
||||||
if (issuesRequest.getTransitions() != null) {
|
|
||||||
paramMap.add("status", issuesRequest.getTransitions().getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
addCustomFields(issuesRequest, paramMap);
|
|
||||||
|
|
||||||
String description = issuesRequest.getDescription();
|
|
||||||
String zentaoSteps = description;
|
|
||||||
|
|
||||||
// transfer description
|
|
||||||
try {
|
|
||||||
zentaoSteps = ms2ZentaoDescription(description);
|
|
||||||
zentaoSteps = zentaoSteps.replaceAll("\\n", "<br/>");
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
LogUtil.info("zentao description transfer: " + zentaoSteps);
|
|
||||||
|
|
||||||
paramMap.add("steps", zentaoSteps);
|
|
||||||
if (!CollectionUtils.isEmpty(issuesRequest.getZentaoBuilds())) {
|
|
||||||
List<String> builds = issuesRequest.getZentaoBuilds();
|
|
||||||
builds.forEach(build -> paramMap.add("openedBuild[]", build));
|
|
||||||
} else {
|
|
||||||
paramMap.add("openedBuild", "trunk");
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotBlank(issuesRequest.getZentaoAssigned())) {
|
|
||||||
paramMap.add("assignedTo", issuesRequest.getZentaoAssigned());
|
|
||||||
}
|
|
||||||
return paramMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteIssue(String id) {
|
|
||||||
IssuesWithBLOBs issuesWithBLOBs = issuesMapper.selectByPrimaryKey(id);
|
|
||||||
super.deleteIssue(id);
|
|
||||||
zentaoClient.deleteIssue(issuesWithBLOBs.getPlatformId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void testAuth() {
|
|
||||||
zentaoClient.login();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void userAuth(UserDTO.PlatformInfo userInfo) {
|
|
||||||
setUserConfig(userInfo);
|
|
||||||
zentaoClient.login();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZentaoConfig getConfig() {
|
|
||||||
return getConfig(key, ZentaoConfig.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZentaoConfig setConfig() {
|
|
||||||
ZentaoConfig config = getConfig();
|
|
||||||
zentaoClient.setConfig(config);
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZentaoConfig setUserConfig() {
|
|
||||||
return setUserConfig(getUserPlatInfo(this.workspaceId));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZentaoConfig setUserConfig(UserDTO.PlatformInfo userPlatInfo) {
|
|
||||||
ZentaoConfig zentaoConfig = getConfig();
|
|
||||||
if (userPlatInfo != null && StringUtils.isNotBlank(userPlatInfo.getZentaoUserName())
|
|
||||||
&& StringUtils.isNotBlank(userPlatInfo.getZentaoPassword())) {
|
|
||||||
zentaoConfig.setAccount(userPlatInfo.getZentaoUserName());
|
|
||||||
zentaoConfig.setPassword(userPlatInfo.getZentaoPassword());
|
|
||||||
}
|
|
||||||
zentaoClient.setConfig(zentaoConfig);
|
|
||||||
return zentaoConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<PlatformUser> getPlatformUser() {
|
|
||||||
String session = zentaoClient.login();
|
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
|
||||||
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(httpHeaders);
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
|
||||||
String getUser = zentaoClient.requestUrl.getUserGet();
|
|
||||||
ResponseEntity<String> responseEntity = restTemplate.exchange(getUser + session,
|
|
||||||
HttpMethod.GET, requestEntity, String.class);
|
|
||||||
String body = responseEntity.getBody();
|
|
||||||
Map obj = JSON.parseMap(body);
|
|
||||||
|
|
||||||
LogUtil.info("zentao user " + obj);
|
|
||||||
|
|
||||||
List data = JSON.parseArray(obj.get("data").toString());
|
|
||||||
|
|
||||||
List<PlatformUser> users = new ArrayList<>();
|
|
||||||
for (int i = 0; i < data.size(); i++) {
|
|
||||||
Map o = (Map) data.get(i);
|
|
||||||
PlatformUser platformUser = new PlatformUser();
|
|
||||||
String account = o.get("account").toString();
|
|
||||||
String username = o.get("realname").toString();
|
|
||||||
platformUser.setName(username);
|
|
||||||
platformUser.setUser(account);
|
|
||||||
users.add(platformUser);
|
|
||||||
}
|
|
||||||
return users;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void syncIssues(Project project, List<IssuesDao> issues) {
|
|
||||||
HashMap<String, List<CustomFieldResourceDTO>> customFieldMap = new HashMap<>();
|
|
||||||
|
|
||||||
issues.forEach(item -> {
|
|
||||||
IssuesWithBLOBs issue = issuesMapper.selectByPrimaryKey(item.getId());
|
|
||||||
Map bug = zentaoClient.getBugById(item.getPlatformId());
|
|
||||||
issue = getUpdateIssues(issue, bug);
|
|
||||||
customFieldMap.put(item.getId(), baseCustomFieldService.getCustomFieldResourceDTO(issue.getCustomFields()));
|
|
||||||
issue.setId(item.getId());
|
|
||||||
issuesMapper.updateByPrimaryKeySelective(issue);
|
|
||||||
syncZentaoIssueAttachments(issue);
|
|
||||||
});
|
|
||||||
customFieldIssuesService.batchEditFields(customFieldMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<ZentaoBuild> getBuilds() {
|
|
||||||
Map<String, Object> builds = zentaoClient.getBuildsByCreateMetaData(getProjectId(projectId));
|
|
||||||
if (builds == null || builds.isEmpty()) {
|
|
||||||
builds = zentaoClient.getBuilds(getProjectId(projectId));
|
|
||||||
}
|
|
||||||
List<ZentaoBuild> res = new ArrayList<>();
|
|
||||||
builds.forEach((k, v) -> {
|
|
||||||
if (StringUtils.isNotBlank(k)) {
|
|
||||||
res.add(new ZentaoBuild(k, v.toString()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String uploadFile(FileSystemResource resource) {
|
|
||||||
String id = "";
|
|
||||||
String session = zentaoClient.login();
|
|
||||||
HttpHeaders httpHeaders = new HttpHeaders();
|
|
||||||
MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
|
|
||||||
paramMap.add("files", resource);
|
|
||||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(paramMap, httpHeaders);
|
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
|
||||||
try {
|
|
||||||
String fileUpload = zentaoClient.requestUrl.getFileUpload();
|
|
||||||
ResponseEntity<String> responseEntity = restTemplate.exchange(fileUpload, HttpMethod.POST, requestEntity,
|
|
||||||
String.class, null, session);
|
|
||||||
String body = responseEntity.getBody();
|
|
||||||
Map obj = JSON.parseMap(body);
|
|
||||||
Map data = (Map) JSON.parseObject(obj.get("data").toString());
|
|
||||||
Set<String> set = data.keySet();
|
|
||||||
if (!set.isEmpty()) {
|
|
||||||
id = (String) set.toArray()[0];
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e, e.getMessage());
|
|
||||||
}
|
|
||||||
LogUtil.info("upload file id: " + id);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String ms2ZentaoDescription(String msDescription) {
|
|
||||||
String imgUrlRegex = "!\\[.*?]\\(/resource/md/get(.*?\\..*?)\\)";
|
|
||||||
String zentaoSteps = msDescription.replaceAll(imgUrlRegex, zentaoClient.requestUrl.getReplaceImgUrl());
|
|
||||||
Matcher matcher = zentaoClient.requestUrl.getImgPattern().matcher(zentaoSteps);
|
|
||||||
while (matcher.find()) {
|
|
||||||
// get file name
|
|
||||||
String originSubUrl = matcher.group(1);
|
|
||||||
if (originSubUrl.contains("/url?url=") || originSubUrl.contains("/path?")) {
|
|
||||||
String path = URLDecoder.decode(originSubUrl, StandardCharsets.UTF_8);
|
|
||||||
String fileName;
|
|
||||||
if (path.indexOf("fileID") > 0) {
|
|
||||||
fileName = path.substring(path.indexOf("fileID") + 7);
|
|
||||||
} else {
|
|
||||||
fileName = path.substring(path.indexOf("file-read-") + 10);
|
|
||||||
}
|
|
||||||
zentaoSteps = zentaoSteps.replaceAll(Pattern.quote(originSubUrl), fileName);
|
|
||||||
} else {
|
|
||||||
String fileName = originSubUrl.substring(10);
|
|
||||||
// get file
|
|
||||||
ResponseEntity<FileSystemResource> mdImage = resourceService.getMdImage(fileName);
|
|
||||||
// upload zentao
|
|
||||||
String id = uploadFile(mdImage.getBody());
|
|
||||||
// todo delete local file
|
|
||||||
int index = fileName.lastIndexOf(".");
|
|
||||||
String suffix = "";
|
|
||||||
if (index != -1) {
|
|
||||||
suffix = fileName.substring(index);
|
|
||||||
}
|
|
||||||
// replace id
|
|
||||||
zentaoSteps = zentaoSteps.replaceAll(Pattern.quote(originSubUrl), id + suffix);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// image link
|
|
||||||
String netImgRegex = "!\\[(.*?)]\\((http.*?)\\)";
|
|
||||||
return zentaoSteps.replaceAll(netImgRegex, "<img src=\"$2\" alt=\"$1\"/>");
|
|
||||||
}
|
|
||||||
|
|
||||||
private String zentao2MsDescription(String ztDescription) {
|
|
||||||
String imgRegex = "<img src.*?/>";
|
|
||||||
Pattern pattern = Pattern.compile(imgRegex);
|
|
||||||
Matcher matcher = pattern.matcher(ztDescription);
|
|
||||||
while (matcher.find()) {
|
|
||||||
if (StringUtils.isNotEmpty(matcher.group())) {
|
|
||||||
// img标签内容
|
|
||||||
String imgPath = matcher.group();
|
|
||||||
// 解析标签内容为图片超链接格式,进行替换,
|
|
||||||
String src = getMatcherResultForImg("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)", imgPath);
|
|
||||||
String alt = getMatcherResultForImg("alt\\s*=\\s*\"?(.*?)(\"|>|\\s+)", imgPath);
|
|
||||||
String hyperLinkPath = packageDescriptionByPathAndName(src, alt);
|
|
||||||
imgPath = transferSpecialCharacter(imgPath);
|
|
||||||
ztDescription = ztDescription.replaceAll(imgPath, hyperLinkPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ztDescription;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String packageDescriptionByPathAndName(String path, String name) {
|
|
||||||
String result = "";
|
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(path)) {
|
|
||||||
if (!path.startsWith("http")) {
|
|
||||||
if (path.startsWith("{") && path.endsWith("}")) {
|
|
||||||
String srcContent = path.substring(1, path.length() - 1);
|
|
||||||
if (StringUtils.isEmpty(name)) {
|
|
||||||
name = srcContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Arrays.stream(imgArray).anyMatch(imgType -> StringUtils.equals(imgType, srcContent.substring(srcContent.indexOf('.') + 1)))) {
|
|
||||||
if (zentaoClient instanceof ZentaoGetClient) {
|
|
||||||
path = zentaoClient.getBaseUrl() + "/index.php?m=file&f=read&fileID=" + srcContent;
|
|
||||||
} else {
|
|
||||||
// 禅道开源版
|
|
||||||
path = zentaoClient.getBaseUrl() + "/file-read-" + srcContent;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
name = name.replaceAll("&", "&");
|
|
||||||
path = path.replaceAll("&", "&");
|
|
||||||
}
|
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
|
||||||
for (String item : path.split("&")) {
|
|
||||||
// 去掉多余的参数
|
|
||||||
if (!StringUtils.containsAny(item, "platform", "workspaceId")) {
|
|
||||||
stringBuilder.append(item);
|
|
||||||
stringBuilder.append("&");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
path = getProxyPath(stringBuilder.toString());
|
|
||||||
}
|
|
||||||
// 图片与描述信息之间需换行,否则无法预览图片
|
|
||||||
result = "\n\n![" + name + "](" + path + ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getMatcherResultForImg(String regex, String targetStr) {
|
|
||||||
String result = "";
|
|
||||||
|
|
||||||
Pattern pattern = Pattern.compile(regex);
|
|
||||||
Matcher matcher = pattern.matcher(targetStr);
|
|
||||||
while (matcher.find()) {
|
|
||||||
result = matcher.group(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean checkProjectExist(String relateId) {
|
|
||||||
return zentaoClient.checkProjectExist(relateId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void syncIssuesAttachment(IssuesUpdateRequest issuesRequest, File file, AttachmentSyncType syncType) {
|
|
||||||
if ("upload".equals(syncType.syncOperateType())) {
|
|
||||||
zentaoClient.uploadAttachment("bug", issuesRequest.getPlatformId(), file);
|
|
||||||
} else if ("delete".equals(syncType.syncOperateType())) {
|
|
||||||
Map bugInfo = zentaoClient.getBugById(issuesRequest.getPlatformId());
|
|
||||||
Map<String, Object> zenFiles = (Map) bugInfo.get("files");
|
|
||||||
for (String fileId : zenFiles.keySet()) {
|
|
||||||
Map fileInfo = (Map) zenFiles.get(fileId);
|
|
||||||
if (file.getName().equals(fileInfo.get("title"))) {
|
|
||||||
zentaoClient.deleteAttachment(fileId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void syncZentaoIssueAttachments(IssuesWithBLOBs issue) {
|
|
||||||
List<String> znetaoAttachmentsName = new ArrayList<String>();
|
|
||||||
AttachmentRequest request = new AttachmentRequest();
|
|
||||||
request.setBelongType(AttachmentType.ISSUE.type());
|
|
||||||
request.setBelongId(issue.getId());
|
|
||||||
List<FileAttachmentMetadata> allMsAttachments = attachmentService.listMetadata(request);
|
|
||||||
List<String> msAttachmentsName = allMsAttachments.stream().map(FileAttachmentMetadata::getName).collect(Collectors.toList());
|
|
||||||
Map bugInfo = zentaoClient.getBugById(issue.getPlatformId());
|
|
||||||
Object files = bugInfo.get("files");
|
|
||||||
Map<String, Object> zenFiles;
|
|
||||||
if (files instanceof List && ((List) files).size() == 0) {
|
|
||||||
zenFiles = null;
|
|
||||||
} else {
|
|
||||||
zenFiles = (Map) files;
|
|
||||||
}
|
|
||||||
// 同步禅道中新的附件
|
|
||||||
if (zenFiles != null) {
|
|
||||||
for (String fileId : zenFiles.keySet()) {
|
|
||||||
Map fileInfo = (Map) zenFiles.get(fileId);
|
|
||||||
String filename = fileInfo.get("title").toString();
|
|
||||||
znetaoAttachmentsName.add(filename);
|
|
||||||
if (!msAttachmentsName.contains(filename)) {
|
|
||||||
try {
|
|
||||||
byte[] bytes = zentaoClient.getAttachmentBytes(fileId);
|
|
||||||
FileAttachmentMetadata fileAttachmentMetadata = attachmentService.saveAttachmentByBytes(bytes, AttachmentType.ISSUE.type(), issue.getId(), filename);
|
|
||||||
AttachmentModuleRelation attachmentModuleRelation = new AttachmentModuleRelation();
|
|
||||||
attachmentModuleRelation.setAttachmentId(fileAttachmentMetadata.getId());
|
|
||||||
attachmentModuleRelation.setRelationId(issue.getId());
|
|
||||||
attachmentModuleRelation.setRelationType(AttachmentType.ISSUE.type());
|
|
||||||
attachmentModuleRelationMapper.insert(attachmentModuleRelation);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LogUtil.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除禅道中不存在的附件
|
|
||||||
if (CollectionUtils.isNotEmpty(allMsAttachments)) {
|
|
||||||
List<FileAttachmentMetadata> deleteMsAttachments = allMsAttachments.stream()
|
|
||||||
.filter(msAttachment -> !znetaoAttachmentsName.contains(msAttachment.getName())).collect(Collectors.toList());
|
|
||||||
deleteMsAttachments.forEach(fileAttachmentMetadata -> {
|
|
||||||
List<String> ids = List.of(fileAttachmentMetadata.getId());
|
|
||||||
AttachmentModuleRelationExample example = new AttachmentModuleRelationExample();
|
|
||||||
example.createCriteria().andAttachmentIdIn(ids).andRelationTypeEqualTo(AttachmentType.ISSUE.type());
|
|
||||||
// 删除MS附件及关联数据
|
|
||||||
attachmentService.deleteAttachmentByIds(ids);
|
|
||||||
attachmentService.deleteFileAttachmentByIds(ids);
|
|
||||||
attachmentModuleRelationMapper.deleteByExample(example);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<PlatformStatusDTO> getTransitions(String issueKey) {
|
|
||||||
List<PlatformStatusDTO> platformStatusDTOS = new ArrayList<>();
|
|
||||||
for (ZentaoIssuePlatformStatus status : ZentaoIssuePlatformStatus.values()) {
|
|
||||||
PlatformStatusDTO platformStatusDTO = new PlatformStatusDTO();
|
|
||||||
platformStatusDTO.setValue(status.name());
|
|
||||||
platformStatusDTO.setLabel(status.getName());
|
|
||||||
|
|
||||||
platformStatusDTOS.add(platformStatusDTO);
|
|
||||||
}
|
|
||||||
return platformStatusDTOS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResponseEntity proxyForGet(String path, Class responseEntityClazz) {
|
|
||||||
return zentaoClient.proxyForGet(path, responseEntityClazz);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +1,9 @@
|
||||||
package io.metersphere.service.wapper;
|
package io.metersphere.service.wapper;
|
||||||
|
|
||||||
import io.metersphere.commons.constants.IssuesManagePlatform;
|
|
||||||
import io.metersphere.service.PlatformPluginService;
|
import io.metersphere.service.PlatformPluginService;
|
||||||
import io.metersphere.service.issue.platform.IssueFactory;
|
|
||||||
import io.metersphere.xpack.track.dto.request.IssuesRequest;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
@ -16,8 +11,6 @@ import javax.annotation.Resource;
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public class IssueProxyResourceService {
|
public class IssueProxyResourceService {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private RestTemplate restTemplate;
|
|
||||||
@Resource
|
@Resource
|
||||||
private PlatformPluginService platformPluginService;
|
private PlatformPluginService platformPluginService;
|
||||||
|
|
||||||
|
@ -25,20 +18,13 @@ public class IssueProxyResourceService {
|
||||||
* http 代理
|
* http 代理
|
||||||
* 如果当前访问地址是 https,直接访问 http 的图片资源
|
* 如果当前访问地址是 https,直接访问 http 的图片资源
|
||||||
* 由于浏览器的安全机制,http 会被转成 https
|
* 由于浏览器的安全机制,http 会被转成 https
|
||||||
|
*
|
||||||
* @param path
|
* @param path
|
||||||
* @param platform
|
* @param platform
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public ResponseEntity<byte[]> getMdImageByPath(String path, String platform, String workspaceId) {
|
public ResponseEntity<byte[]> getMdImageByPath(String path, String platform, String workspaceId) {
|
||||||
if (StringUtils.equals(IssuesManagePlatform.Zentao.name(), platform)) {
|
|
||||||
IssuesRequest issuesRequest = new IssuesRequest();
|
|
||||||
issuesRequest.setWorkspaceId(workspaceId);
|
|
||||||
return IssueFactory.createPlatform(platform, issuesRequest)
|
|
||||||
.proxyForGet(path, byte[].class);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return platformPluginService.getPlatform(platform, workspaceId)
|
return platformPluginService.getPlatform(platform, workspaceId)
|
||||||
.proxyForGet(path, byte[].class);
|
.proxyForGet(path, byte[].class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -20,6 +20,9 @@ public class PluginManagerUtil {
|
||||||
* @param inputStream
|
* @param inputStream
|
||||||
*/
|
*/
|
||||||
public static void loadPlugin(String id, PluginManager pluginManager, InputStream inputStream) {
|
public static void loadPlugin(String id, PluginManager pluginManager, InputStream inputStream) {
|
||||||
|
if (inputStream == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (pluginManager == null) {
|
if (pluginManager == null) {
|
||||||
pluginManager = new PluginManager();
|
pluginManager = new PluginManager();
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,14 +56,6 @@ export function getIssues(currentPage, pageSize, param) {
|
||||||
return post(BASE_URL + "list/" + currentPage + '/' + pageSize, param);
|
return post(BASE_URL + "list/" + currentPage + '/' + pageSize, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getZentaoBuilds(param) {
|
|
||||||
return post(BASE_URL + "zentao/builds", param);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getZentaoUser(param) {
|
|
||||||
return post(BASE_URL + "zentao/user", param);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getTapdUser(param) {
|
export function getTapdUser(param) {
|
||||||
return post(BASE_URL + "tapd/user", param);
|
return post(BASE_URL + "tapd/user", param);
|
||||||
}
|
}
|
||||||
|
@ -184,16 +176,22 @@ export function deleteIssueRelate(param) {
|
||||||
return post('/issues/delete/relate', param);
|
return post('/issues/delete/relate', param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseOptions(customFields) {
|
||||||
|
if (customFields) {
|
||||||
|
customFields.forEach(item => {
|
||||||
|
if (item.options) {
|
||||||
|
item.options = JSON.parse(item.options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getIssueThirdPartTemplate() {
|
export function getIssueThirdPartTemplate() {
|
||||||
return get('/issues/thirdpart/template/' + getCurrentProjectID())
|
return get('/issues/thirdpart/template/' + getCurrentProjectID())
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
let template = response.data;
|
let template = response.data;
|
||||||
if (template.customFields) {
|
if (template.customFields) {
|
||||||
template.customFields.forEach(item => {
|
parseOptions(template.customFields);
|
||||||
if (item.options) {
|
|
||||||
item.options = JSON.parse(item.options);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return template
|
return template
|
||||||
});
|
});
|
||||||
|
@ -210,8 +208,8 @@ export function getJiraIssueType(param) {
|
||||||
return post('/issues/jira/issuetype', param);
|
return post('/issues/jira/issuetype', param);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPlatformTransitions(param) {
|
export function getPlatformStatus(param) {
|
||||||
return post('/issues/platform/transitions', param);
|
return post('/issues/platform/status', param);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function enableThirdPartTemplate(projectId) {
|
export function enableThirdPartTemplate(projectId) {
|
||||||
|
@ -229,6 +227,10 @@ export function buildIssues(page) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPluginCustomFields(projectId) {
|
||||||
|
return get(BASE_URL + `plugin/custom/fields/${projectId}`);
|
||||||
|
}
|
||||||
|
|
||||||
export function getIssuePartTemplateWithProject(callback) {
|
export function getIssuePartTemplateWithProject(callback) {
|
||||||
getCurrentProject().then((response) => {
|
getCurrentProject().then((response) => {
|
||||||
let currentProject = response.data;
|
let currentProject = response.data;
|
||||||
|
@ -241,8 +243,13 @@ export function getIssuePartTemplateWithProject(callback) {
|
||||||
callback(template, currentProject);
|
callback(template, currentProject);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
getIssueTemplate()
|
Promise.all([getPluginCustomFields(currentProject.id), getIssueTemplate()])
|
||||||
.then((template) => {
|
.then(data => {
|
||||||
|
let pluginFields = data[0].data;
|
||||||
|
parseOptions(pluginFields);
|
||||||
|
|
||||||
|
let template = data[1];
|
||||||
|
template.customFields.push(...pluginFields);
|
||||||
if (callback)
|
if (callback)
|
||||||
callback(template, currentProject);
|
callback(template, currentProject);
|
||||||
});
|
});
|
||||||
|
|
|
@ -76,26 +76,6 @@
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8" v-if="hasZentaoId">
|
|
||||||
<el-form-item :label-width="formLabelWidth" :label="$t('test_track.issue.zentao_bug_build')"
|
|
||||||
prop="zentaoBuilds">
|
|
||||||
<el-select v-model="form.zentaoBuilds" multiple filterable
|
|
||||||
:placeholder="$t('test_track.issue.zentao_bug_build')">
|
|
||||||
<el-option v-for="(build, index) in Builds" :key="index" :label="build.name"
|
|
||||||
:value="build.id"/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="8" v-if="hasZentaoId">
|
|
||||||
<el-form-item :label-width="formLabelWidth" :label="$t('test_track.issue.zentao_bug_assigned')"
|
|
||||||
prop="zentaoAssigned">
|
|
||||||
<el-select v-model="form.zentaoAssigned" filterable
|
|
||||||
:placeholder="$t('test_track.issue.please_choose_current_owner')">
|
|
||||||
<el-option v-for="(userInfo, index) in zentaoUsers" :key="index" :label="userInfo.name"
|
|
||||||
:value="userInfo.user"/>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<ms-form-divider :title="$t('test_track.case.other_info')"/>
|
<ms-form-divider :title="$t('test_track.case.other_info')"/>
|
||||||
|
@ -220,14 +200,12 @@ import {hasLicense} from "metersphere-frontend/src/utils/permission";
|
||||||
import {
|
import {
|
||||||
enableThirdPartTemplate,
|
enableThirdPartTemplate,
|
||||||
getIssuePartTemplateWithProject,
|
getIssuePartTemplateWithProject,
|
||||||
getPlatformTransitions,
|
getPlatformStatus,
|
||||||
getIssuesById,
|
getIssuesById,
|
||||||
saveOrUpdateIssue,
|
saveOrUpdateIssue,
|
||||||
saveFollow,
|
saveFollow,
|
||||||
getFollow,
|
getFollow,
|
||||||
getComments,
|
getComments,
|
||||||
getZentaoBuilds,
|
|
||||||
getZentaoUser,
|
|
||||||
getTapdUser
|
getTapdUser
|
||||||
} from "@/api/issue";
|
} from "@/api/issue";
|
||||||
import {
|
import {
|
||||||
|
@ -293,16 +271,11 @@ export default {
|
||||||
creator: null,
|
creator: null,
|
||||||
remark: null,
|
remark: null,
|
||||||
tapdUsers: [],
|
tapdUsers: [],
|
||||||
zentaoBuilds: [],
|
|
||||||
zentaoAssigned: '',
|
|
||||||
platformStatus: null,
|
platformStatus: null,
|
||||||
copyIssueId: ''
|
copyIssueId: ''
|
||||||
},
|
},
|
||||||
tapdUsers: [],
|
tapdUsers: [],
|
||||||
zentaoUsers: [],
|
|
||||||
Builds: [],
|
|
||||||
hasTapdId: false,
|
hasTapdId: false,
|
||||||
hasZentaoId: false,
|
|
||||||
platformTransitions: null,
|
platformTransitions: null,
|
||||||
currentProject: null,
|
currentProject: null,
|
||||||
toolbars: {
|
toolbars: {
|
||||||
|
@ -392,8 +365,6 @@ export default {
|
||||||
creator: null,
|
creator: null,
|
||||||
remark: null,
|
remark: null,
|
||||||
tapdUsers: [],
|
tapdUsers: [],
|
||||||
zentaoBuilds: [],
|
|
||||||
zentaoAssigned: '',
|
|
||||||
platformStatus: null
|
platformStatus: null
|
||||||
};
|
};
|
||||||
this.customFieldForm = null;
|
this.customFieldForm = null;
|
||||||
|
@ -438,11 +409,6 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
getIssuesById(data.id).then(response => {
|
|
||||||
this.form.tapdUsers = response.data.tapdUsers;
|
|
||||||
this.form.zentaoBuilds = response.data.zentaoBuilds;
|
|
||||||
this.form.zentaoAssigned = response.data.zentaoAssigned;
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
this.issueId = null;
|
this.issueId = null;
|
||||||
this.form.follows = [];
|
this.form.follows = [];
|
||||||
|
@ -467,7 +433,7 @@ export default {
|
||||||
projectId: getCurrentProjectID(),
|
projectId: getCurrentProjectID(),
|
||||||
workspaceId: getCurrentWorkspaceId()
|
workspaceId: getCurrentWorkspaceId()
|
||||||
}
|
}
|
||||||
getPlatformTransitions(data).then(response => {
|
getPlatformStatus(data).then(response => {
|
||||||
if (response.data.length > 0) {
|
if (response.data.length > 0) {
|
||||||
this.platformTransitions = response.data;
|
this.platformTransitions = response.data;
|
||||||
}
|
}
|
||||||
|
@ -478,19 +444,7 @@ export default {
|
||||||
projectId: this.projectId,
|
projectId: this.projectId,
|
||||||
workspaceId: getCurrentWorkspaceId()
|
workspaceId: getCurrentWorkspaceId()
|
||||||
}
|
}
|
||||||
if (platform === 'Zentao') {
|
if (platform === 'Tapd') {
|
||||||
this.hasZentaoId = true;
|
|
||||||
getZentaoBuilds(data)
|
|
||||||
.then((response) => {
|
|
||||||
if (response.data) {
|
|
||||||
this.Builds = response.data;
|
|
||||||
}
|
|
||||||
getZentaoUser(data)
|
|
||||||
.then((response) => {
|
|
||||||
this.zentaoUsers = response.data;
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else if (platform === 'Tapd') {
|
|
||||||
this.hasTapdId = true;
|
this.hasTapdId = true;
|
||||||
getTapdUser(data)
|
getTapdUser(data)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
|
|
|
@ -171,7 +171,6 @@ import StatusTableItem from "@/business/common/tableItems/planview/StatusTableIt
|
||||||
import {testPlanTestCaseEdit, testPlanTestCaseGet} from "@/api/remote/plan/test-plan-test-case";
|
import {testPlanTestCaseEdit, testPlanTestCaseGet} from "@/api/remote/plan/test-plan-test-case";
|
||||||
import {testPlanEditStatus} from "@/api/remote/plan/test-plan";
|
import {testPlanEditStatus} from "@/api/remote/plan/test-plan";
|
||||||
import {getTestTemplate} from "@/api/custom-field-template";
|
import {getTestTemplate} from "@/api/custom-field-template";
|
||||||
import {getCurrentProjectID} from "@/business/utils/sdk-utils";
|
|
||||||
import {checkProjectPermission} from "@/api/testCase";
|
import {checkProjectPermission} from "@/api/testCase";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -204,12 +203,6 @@ export default {
|
||||||
test: {},
|
test: {},
|
||||||
activeTab: 'detail',
|
activeTab: 'detail',
|
||||||
users: [],
|
users: [],
|
||||||
Builds: [],
|
|
||||||
zentaoBuilds: [],
|
|
||||||
zentaoUsers: [],
|
|
||||||
zentaoAssigned: "",
|
|
||||||
hasTapdId: false,
|
|
||||||
hasZentaoId: false,
|
|
||||||
tableData: [],
|
tableData: [],
|
||||||
comments: [],
|
comments: [],
|
||||||
testCaseTemplate: {},
|
testCaseTemplate: {},
|
||||||
|
@ -445,8 +438,6 @@ export default {
|
||||||
});
|
});
|
||||||
this.showDialog = true;
|
this.showDialog = true;
|
||||||
this.activeTab = 'detail';
|
this.activeTab = 'detail';
|
||||||
this.hasTapdId = false;
|
|
||||||
this.hasZentaoId = false;
|
|
||||||
this.originalStatus = testCase.status;
|
this.originalStatus = testCase.status;
|
||||||
this.setTitleWith();
|
this.setTitleWith();
|
||||||
|
|
||||||
|
|
|
@ -206,8 +206,6 @@ export default {
|
||||||
api: {},
|
api: {},
|
||||||
apiCase: {},
|
apiCase: {},
|
||||||
testCaseTemplate: {},
|
testCaseTemplate: {},
|
||||||
hasTapdId: false,
|
|
||||||
hasZentaoId: false,
|
|
||||||
formLabelWidth: '100px',
|
formLabelWidth: '100px',
|
||||||
isCustomFiledActive: false,
|
isCustomFiledActive: false,
|
||||||
oldReviewStatus: '',
|
oldReviewStatus: '',
|
||||||
|
@ -408,8 +406,6 @@ export default {
|
||||||
// 一开始加载时候需要保存用例评审旧的状态
|
// 一开始加载时候需要保存用例评审旧的状态
|
||||||
this.oldReviewStatus = testCase.reviewStatus;
|
this.oldReviewStatus = testCase.reviewStatus;
|
||||||
this.activeTab = 'detail';
|
this.activeTab = 'detail';
|
||||||
this.hasTapdId = false;
|
|
||||||
this.hasZentaoId = false;
|
|
||||||
listenGoBack(this.handleClose);
|
listenGoBack(this.handleClose);
|
||||||
let initFuc = this.getTestCase;
|
let initFuc = this.getTestCase;
|
||||||
this.setTitleWith();
|
this.setTitleWith();
|
||||||
|
|
Loading…
Reference in New Issue