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.metadata.service.FileManagerService;
|
||||
import io.metersphere.metadata.vo.FileRequest;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -28,6 +29,17 @@ public class BasePluginService {
|
|||
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) {
|
||||
FileRequest request = new FileRequest();
|
||||
request.setProjectId(DIR_PATH + "/" + pluginId);
|
||||
|
@ -38,6 +50,9 @@ public class BasePluginService {
|
|||
|
||||
public InputStream getPluginJar(String pluginId) {
|
||||
PluginWithBLOBs plugin = pluginMapper.selectByPrimaryKey(pluginId);
|
||||
if (plugin == null) {
|
||||
return null;
|
||||
}
|
||||
return getPluginResource(pluginId, plugin.getSourceName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ public class IssuesDao extends IssuesWithBLOBs {
|
|||
private List<String> caseIds;
|
||||
private String caseId;
|
||||
private List<String> tapdUsers;
|
||||
private List<String>zentaoBuilds;
|
||||
private String zentaoAssigned;
|
||||
private String refType;
|
||||
private String refId;
|
||||
private List<CustomFieldDao> fields;
|
||||
|
|
|
@ -21,14 +21,6 @@ public class IssuesRequest extends BaseQueryRequest {
|
|||
* 如果是 PLAN_FUNCTIONAL 则只查询该测试计划用例所关联的缺陷
|
||||
*/
|
||||
private String refType;
|
||||
/**
|
||||
* zentao bug 处理人
|
||||
*/
|
||||
private String zentaoUser;
|
||||
/**
|
||||
* zentao bug 影响版本
|
||||
*/
|
||||
private List<String> zentaoBuilds;
|
||||
|
||||
/**
|
||||
* issues id
|
||||
|
|
|
@ -22,15 +22,6 @@ public class IssuesUpdateRequest extends IssuesWithBLOBs {
|
|||
private List<CustomFieldResourceDTO> addFields;
|
||||
private List<CustomFieldResourceDTO> editFields;
|
||||
private List<CustomFieldItemDTO> requestFields;
|
||||
/**
|
||||
* zentao bug 处理人
|
||||
*/
|
||||
private String zentaoUser;
|
||||
private String zentaoAssigned;
|
||||
/**
|
||||
* zentao bug 影响版本
|
||||
*/
|
||||
private List<String> zentaoBuilds;
|
||||
private boolean thirdPartPlatform;
|
||||
|
||||
private List<String> follows;
|
||||
|
|
|
@ -55,6 +55,9 @@ public class PluginManagerUtil {
|
|||
* @param pluginManager
|
||||
*/
|
||||
public static void loadPlugin(String id, PluginManager pluginManager, InputStream inputStream) {
|
||||
if (inputStream == null) {
|
||||
return;
|
||||
}
|
||||
if (pluginManager == null) {
|
||||
pluginManager = new PluginManager();
|
||||
}
|
||||
|
|
|
@ -31,15 +31,14 @@
|
|||
|
||||
<script>
|
||||
import TapdSetting from '@/business/workspace/integration/TapdSetting';
|
||||
import JiraSetting from '@/business/workspace/integration/JiraSetting';
|
||||
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 {generatePlatformResourceUrl, getIntegrationInfo} from "@/api/platform-plugin";
|
||||
|
||||
export default {
|
||||
name: "BugManagement",
|
||||
components: {PlatformConfig, TapdSetting, JiraSetting, AzuredevopsSetting},
|
||||
components: {PlatformConfig, TapdSetting, AzuredevopsSetting},
|
||||
data() {
|
||||
return {
|
||||
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
|
||||
else cfi.value end as value
|
||||
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}
|
||||
</select>
|
||||
<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.utils.PageUtils;
|
||||
import io.metersphere.commons.utils.Pager;
|
||||
import io.metersphere.dto.CustomFieldDao;
|
||||
import io.metersphere.dto.IssuesStatusCountDao;
|
||||
import io.metersphere.excel.domain.ExcelResponse;
|
||||
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.IssuesService;
|
||||
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.request.IssuesRequest;
|
||||
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
|
||||
|
@ -150,16 +150,6 @@ public class IssuesController {
|
|||
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}")
|
||||
public boolean syncThirdPartyIssues(@PathVariable String projectId) {
|
||||
return issuesService.syncThirdPartyIssues(projectId);
|
||||
|
@ -200,6 +190,11 @@ public class IssuesController {
|
|||
return issuesService.getThirdPartTemplate(projectId);
|
||||
}
|
||||
|
||||
@GetMapping("/plugin/custom/fields/{projectId}")
|
||||
public List<CustomFieldDao> getPluginCustomFields(@PathVariable String projectId) {
|
||||
return issuesService.getPluginCustomFields(projectId);
|
||||
}
|
||||
|
||||
@GetMapping("/demand/list/{projectId}")
|
||||
public List getDemandList(@PathVariable String 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.testcase.AuthUserIssueRequest;
|
||||
import io.metersphere.request.testcase.IssuesCountRequest;
|
||||
import io.metersphere.service.issue.domain.zentao.ZentaoBuild;
|
||||
import io.metersphere.service.issue.platform.*;
|
||||
import io.metersphere.service.remote.project.TrackCustomFieldTemplateService;
|
||||
import io.metersphere.service.remote.project.TrackIssueTemplateService;
|
||||
|
@ -141,6 +140,8 @@ public class IssuesService {
|
|||
private PlatformPluginService platformPluginService;
|
||||
@Resource
|
||||
private UserService userService;
|
||||
@Resource
|
||||
private BasePluginService basePluginService;
|
||||
|
||||
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());
|
||||
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);
|
||||
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) {
|
||||
request.setOrders(ServiceUtils.getDefaultOrderByField(request.getOrders(), "create_time"));
|
||||
request.getOrders().forEach(order -> {
|
||||
|
@ -1148,6 +1133,8 @@ public class IssuesService {
|
|||
public String getDefaultCustomFields(String projectId) {
|
||||
IssueTemplateDao template = trackIssueTemplateService.getTemplate(projectId);
|
||||
List<CustomFieldDao> customFields = trackCustomFieldTemplateService.getCustomFieldByTemplateId(template.getId());
|
||||
List<CustomFieldDao> pluginCustomFields = getPluginCustomFields(projectId);
|
||||
customFields.addAll(pluginCustomFields);
|
||||
return getCustomFieldsValuesString(customFields);
|
||||
}
|
||||
|
||||
|
@ -1370,6 +1357,47 @@ public class IssuesService {
|
|||
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) {
|
||||
IssuesRequest issuesRequest = new IssuesRequest();
|
||||
issuesRequest.setProjectId(projectId);
|
||||
|
@ -1443,9 +1471,6 @@ public class IssuesService {
|
|||
if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Tapd.name())) {
|
||||
TapdPlatform tapd = new TapdPlatform(issuesRequest);
|
||||
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.platform.domain.PlatformRequest;
|
||||
import io.metersphere.platform.domain.SelectOption;
|
||||
|
||||
import io.metersphere.platform.loader.PlatformPluginManager;
|
||||
import io.metersphere.request.IntegrationRequest;
|
||||
import io.metersphere.utils.PluginManagerUtil;
|
||||
|
@ -122,8 +123,7 @@ public class PlatformPluginService {
|
|||
|
||||
public static boolean isPluginPlatform(String platform) {
|
||||
if (StringUtils.equalsAnyIgnoreCase(platform,
|
||||
IssuesManagePlatform.Tapd.name(), IssuesManagePlatform.AzureDevops.name(),
|
||||
IssuesManagePlatform.Zentao.name(), IssuesManagePlatform.Local.name())) {
|
||||
IssuesManagePlatform.Tapd.name(), IssuesManagePlatform.AzureDevops.name(), IssuesManagePlatform.Local.name())) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
if (StringUtils.equals(IssuesManagePlatform.Tapd.toString(), platform)) {
|
||||
return new TapdPlatform(addIssueRequest);
|
||||
} else if (StringUtils.equals(IssuesManagePlatform.Zentao.toString(), platform)) {
|
||||
return new ZentaoPlatform(addIssueRequest);
|
||||
} else if (StringUtils.equals(IssuesManagePlatform.AzureDevops.toString(), platform)) {
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
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;
|
||||
|
||||
import io.metersphere.commons.constants.IssuesManagePlatform;
|
||||
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.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
@ -16,8 +11,6 @@ import javax.annotation.Resource;
|
|||
@Transactional(rollbackFor = Exception.class)
|
||||
public class IssueProxyResourceService {
|
||||
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
@Resource
|
||||
private PlatformPluginService platformPluginService;
|
||||
|
||||
|
@ -25,20 +18,13 @@ public class IssueProxyResourceService {
|
|||
* http 代理
|
||||
* 如果当前访问地址是 https,直接访问 http 的图片资源
|
||||
* 由于浏览器的安全机制,http 会被转成 https
|
||||
*
|
||||
* @param path
|
||||
* @param platform
|
||||
* @return
|
||||
*/
|
||||
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)
|
||||
.proxyForGet(path, byte[].class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@ public class PluginManagerUtil {
|
|||
* @param inputStream
|
||||
*/
|
||||
public static void loadPlugin(String id, PluginManager pluginManager, InputStream inputStream) {
|
||||
if (inputStream == null) {
|
||||
return;
|
||||
}
|
||||
if (pluginManager == null) {
|
||||
pluginManager = new PluginManager();
|
||||
}
|
||||
|
|
|
@ -56,14 +56,6 @@ export function getIssues(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) {
|
||||
return post(BASE_URL + "tapd/user", param);
|
||||
}
|
||||
|
@ -184,16 +176,22 @@ export function deleteIssueRelate(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() {
|
||||
return get('/issues/thirdpart/template/' + getCurrentProjectID())
|
||||
.then((response) => {
|
||||
let template = response.data;
|
||||
if (template.customFields) {
|
||||
template.customFields.forEach(item => {
|
||||
if (item.options) {
|
||||
item.options = JSON.parse(item.options);
|
||||
}
|
||||
});
|
||||
parseOptions(template.customFields);
|
||||
}
|
||||
return template
|
||||
});
|
||||
|
@ -210,8 +208,8 @@ export function getJiraIssueType(param) {
|
|||
return post('/issues/jira/issuetype', param);
|
||||
}
|
||||
|
||||
export function getPlatformTransitions(param) {
|
||||
return post('/issues/platform/transitions', param);
|
||||
export function getPlatformStatus(param) {
|
||||
return post('/issues/platform/status', param);
|
||||
}
|
||||
|
||||
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) {
|
||||
getCurrentProject().then((response) => {
|
||||
let currentProject = response.data;
|
||||
|
@ -241,8 +243,13 @@ export function getIssuePartTemplateWithProject(callback) {
|
|||
callback(template, currentProject);
|
||||
});
|
||||
} else {
|
||||
getIssueTemplate()
|
||||
.then((template) => {
|
||||
Promise.all([getPluginCustomFields(currentProject.id), getIssueTemplate()])
|
||||
.then(data => {
|
||||
let pluginFields = data[0].data;
|
||||
parseOptions(pluginFields);
|
||||
|
||||
let template = data[1];
|
||||
template.customFields.push(...pluginFields);
|
||||
if (callback)
|
||||
callback(template, currentProject);
|
||||
});
|
||||
|
|
|
@ -76,26 +76,6 @@
|
|||
</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_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>
|
||||
|
||||
<ms-form-divider :title="$t('test_track.case.other_info')"/>
|
||||
|
@ -220,14 +200,12 @@ import {hasLicense} from "metersphere-frontend/src/utils/permission";
|
|||
import {
|
||||
enableThirdPartTemplate,
|
||||
getIssuePartTemplateWithProject,
|
||||
getPlatformTransitions,
|
||||
getPlatformStatus,
|
||||
getIssuesById,
|
||||
saveOrUpdateIssue,
|
||||
saveFollow,
|
||||
getFollow,
|
||||
getComments,
|
||||
getZentaoBuilds,
|
||||
getZentaoUser,
|
||||
getTapdUser
|
||||
} from "@/api/issue";
|
||||
import {
|
||||
|
@ -293,16 +271,11 @@ export default {
|
|||
creator: null,
|
||||
remark: null,
|
||||
tapdUsers: [],
|
||||
zentaoBuilds: [],
|
||||
zentaoAssigned: '',
|
||||
platformStatus: null,
|
||||
copyIssueId: ''
|
||||
},
|
||||
tapdUsers: [],
|
||||
zentaoUsers: [],
|
||||
Builds: [],
|
||||
hasTapdId: false,
|
||||
hasZentaoId: false,
|
||||
platformTransitions: null,
|
||||
currentProject: null,
|
||||
toolbars: {
|
||||
|
@ -392,8 +365,6 @@ export default {
|
|||
creator: null,
|
||||
remark: null,
|
||||
tapdUsers: [],
|
||||
zentaoBuilds: [],
|
||||
zentaoAssigned: '',
|
||||
platformStatus: 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 {
|
||||
this.issueId = null;
|
||||
this.form.follows = [];
|
||||
|
@ -467,7 +433,7 @@ export default {
|
|||
projectId: getCurrentProjectID(),
|
||||
workspaceId: getCurrentWorkspaceId()
|
||||
}
|
||||
getPlatformTransitions(data).then(response => {
|
||||
getPlatformStatus(data).then(response => {
|
||||
if (response.data.length > 0) {
|
||||
this.platformTransitions = response.data;
|
||||
}
|
||||
|
@ -478,19 +444,7 @@ export default {
|
|||
projectId: this.projectId,
|
||||
workspaceId: getCurrentWorkspaceId()
|
||||
}
|
||||
if (platform === 'Zentao') {
|
||||
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') {
|
||||
if (platform === 'Tapd') {
|
||||
this.hasTapdId = true;
|
||||
getTapdUser(data)
|
||||
.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 {testPlanEditStatus} from "@/api/remote/plan/test-plan";
|
||||
import {getTestTemplate} from "@/api/custom-field-template";
|
||||
import {getCurrentProjectID} from "@/business/utils/sdk-utils";
|
||||
import {checkProjectPermission} from "@/api/testCase";
|
||||
|
||||
export default {
|
||||
|
@ -204,12 +203,6 @@ export default {
|
|||
test: {},
|
||||
activeTab: 'detail',
|
||||
users: [],
|
||||
Builds: [],
|
||||
zentaoBuilds: [],
|
||||
zentaoUsers: [],
|
||||
zentaoAssigned: "",
|
||||
hasTapdId: false,
|
||||
hasZentaoId: false,
|
||||
tableData: [],
|
||||
comments: [],
|
||||
testCaseTemplate: {},
|
||||
|
@ -445,8 +438,6 @@ export default {
|
|||
});
|
||||
this.showDialog = true;
|
||||
this.activeTab = 'detail';
|
||||
this.hasTapdId = false;
|
||||
this.hasZentaoId = false;
|
||||
this.originalStatus = testCase.status;
|
||||
this.setTitleWith();
|
||||
|
||||
|
|
|
@ -206,8 +206,6 @@ export default {
|
|||
api: {},
|
||||
apiCase: {},
|
||||
testCaseTemplate: {},
|
||||
hasTapdId: false,
|
||||
hasZentaoId: false,
|
||||
formLabelWidth: '100px',
|
||||
isCustomFiledActive: false,
|
||||
oldReviewStatus: '',
|
||||
|
@ -408,8 +406,6 @@ export default {
|
|||
// 一开始加载时候需要保存用例评审旧的状态
|
||||
this.oldReviewStatus = testCase.reviewStatus;
|
||||
this.activeTab = 'detail';
|
||||
this.hasTapdId = false;
|
||||
this.hasZentaoId = false;
|
||||
listenGoBack(this.handleClose);
|
||||
let initFuc = this.getTestCase;
|
||||
this.setTitleWith();
|
||||
|
|
Loading…
Reference in New Issue