refactor(项目设置): 检查三方平台关联项目有效性

--bug=1010673 --user=李玉号 【项目设置】-zentao/tapd 编辑项目 写入无效的项目id
,进入缺陷管理,创建缺陷会报错 https://www.tapd.cn/55049933/s/1115973
This commit is contained in:
shiziyuan9527 2022-03-10 10:55:22 +08:00 committed by shiziyuan9527
parent 6c0dcb5e7d
commit fd51593dc0
20 changed files with 143 additions and 6 deletions

View File

@ -152,4 +152,9 @@ public class ProjectController {
public boolean isVersionEnable(@PathVariable String projectId) {
return projectService.isVersionEnable(projectId);
}
@PostMapping("/check/third/project")
public void checkThirdProjectExist(@RequestBody Project project) {
projectService.checkThirdProjectExist(project);
}
}

View File

@ -36,6 +36,11 @@ import io.metersphere.performance.request.DeleteTestPlanRequest;
import io.metersphere.performance.request.QueryProjectFileRequest;
import io.metersphere.performance.service.PerformanceReportService;
import io.metersphere.performance.service.PerformanceTestService;
import io.metersphere.track.issue.AbstractIssuePlatform;
import io.metersphere.track.issue.JiraPlatform;
import io.metersphere.track.issue.TapdPlatform;
import io.metersphere.track.issue.ZentaoPlatform;
import io.metersphere.track.request.testcase.IssuesRequest;
import io.metersphere.track.service.TestCaseService;
import io.metersphere.track.service.TestPlanProjectService;
import io.metersphere.track.service.TestPlanReportService;
@ -188,6 +193,35 @@ public class ProjectService {
return project;
}
public void checkThirdProjectExist(Project project) {
IssuesRequest issuesRequest = new IssuesRequest();
if (StringUtils.isBlank(project.getId())) {
MSException.throwException("project ID cannot be empty");
}
issuesRequest.setProjectId(project.getId());
issuesRequest.setWorkspaceId(project.getWorkspaceId());
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.Jira.name())) {
JiraPlatform jira = new JiraPlatform(issuesRequest);
this.doCheckThirdProjectExist(jira, project.getJiraKey());
} else if (StringUtils.equalsIgnoreCase(project.getPlatform(), IssuesManagePlatform.Zentao.name())) {
ZentaoPlatform zentao = new ZentaoPlatform(issuesRequest);
this.doCheckThirdProjectExist(zentao, project.getZentaoId());
}
}
private void doCheckThirdProjectExist(AbstractIssuePlatform platform, String relateId) {
if (StringUtils.isBlank(relateId)) {
MSException.throwException(Translator.get("issue_project_not_exist"));
}
Boolean exist = platform.checkProjectExist(relateId);
if (BooleanUtils.isFalse(exist)) {
MSException.throwException(Translator.get("issue_project_not_exist"));
}
}
private String genSystemId() {
String maxSystemIdInDb = extProjectMapper.getMaxSystemId();
String systemId = "10001";

View File

@ -522,4 +522,9 @@ public abstract class AbstractIssuePlatform implements IssuesPlatform {
}
return false;
}
@Override
public Boolean checkProjectExist(String relateId) {
return null;
}
}

View File

@ -78,4 +78,11 @@ public interface IssuesPlatform {
* @return
*/
IssueTemplateDao getThirdPartTemplate();
/**
* 检查其它平台关联的ID是否存在
* @param relateId 其它平台在MS项目上关联的相关ID
* @return Boolean
*/
Boolean checkProjectExist(String relateId);
}

View File

@ -133,7 +133,11 @@ public class JiraPlatform extends AbstractIssuePlatform {
}
public List<JiraIssueType> getIssueTypes(String jiraKey) {
return jiraClientV2.getIssueType(jiraKey);
try {
return jiraClientV2.getIssueType(jiraKey);
} catch (Exception e) {
return null;
}
}
@Override
@ -648,4 +652,17 @@ public class JiraPlatform extends AbstractIssuePlatform {
});
return options.toJSONString();
}
@Override
public Boolean checkProjectExist(String relateId) {
try {
JiraIssueProject project = jiraClientV2.getProject(relateId);
if (project != null && StringUtils.isNotBlank(project.getId())) {
return true;
}
} catch (Exception e) {
return false;
}
return false;
}
}

View File

@ -264,4 +264,13 @@ public class TapdPlatform extends AbstractIssuePlatform {
}
return null;
}
@Override
public Boolean checkProjectExist(String relateId) {
try {
return tapdClient.checkProjectExist(relateId);
} catch (Exception e) {
return false;
}
}
}

View File

@ -409,4 +409,9 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
String imgRegex = "<img src.*?/>";
return ztDescription.replaceAll(imgRegex, "");
}
@Override
public Boolean checkProjectExist(String relateId) {
return zentaoClient.checkProjectExist(relateId);
}
}

View File

@ -117,4 +117,11 @@ public class TapdClient extends BaseClient {
USER_NAME = config.getAccount();
PASSWD = config.getPassword();
}
public boolean checkProjectExist(String relateId) {
String url = getBaseUrl() + "/roles?workspace_id={1}";
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class, relateId);
TapdGetIssueResponse res = (TapdGetIssueResponse) getResultForObject(TapdGetIssueResponse.class, response);
return res == null || res.getStatus() != 404;
}
}

View File

@ -188,4 +188,19 @@ public abstract class ZentaoClient extends BaseClient {
}
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 = JSONObject.parseObject(response.getBody()).get("data");
if (!StringUtils.equals((String) data, "false")) {
return true;
}
} catch (Exception e) {
LogUtil.info("query zentao product info error. product id: " + relateId);
}
return false;
}
}

View File

@ -19,6 +19,7 @@ public class ZentaoGetClient extends ZentaoClient {
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&params=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=&param=0&orderBy=&recTotal={1}&recPerPage={2}&pageID={3}&t=json&zentaosid={4}";
@ -43,6 +44,7 @@ public class ZentaoGetClient extends ZentaoClient {
request.setBugDelete(getNotSuperModelUrl(BUG_DELETE));
request.setBugList(getNotSuperModelUrl(BUG_LIST_URL));
request.setCreateMetaData(getNotSuperModelUrl(CREATE_META_DATA));
request.setProductGet(getUrl(PRODUCT_GET));
requestUrl = request;
}

View File

@ -20,6 +20,7 @@ public class ZentaoPathInfoClient extends ZentaoClient {
private static final String FILE_UPLOAD = "/api-getModel-file-saveUpload.json?zentaosid=";
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--{2}-{3}-{4}.json?zentaosid={5}";
@ -44,6 +45,7 @@ public class ZentaoPathInfoClient extends ZentaoClient {
request.setBugDelete(getUrl(BUG_DELETE));
request.setBugList(getUrl(BUG_LIST_URL));
request.setCreateMetaData(getUrl(CREATE_META_DATA));
request.setProductGet(getUrl(PRODUCT_GET));
requestUrl = request;
}

View File

@ -21,5 +21,6 @@ public class RequestUrl {
private String buildsGet;
private String fileUpload;
private String replaceImgUrl;
private String productGet;
private Pattern imgPattern;
}

View File

@ -163,6 +163,7 @@ id_required=ID required
id_repeat_in_table=ID is repeat in table
step_model_tip=Step description fill in STEP, text description please fill in TEXT (not required)
case_status_not_exist=The use case status must be Prepare, Underway way and Completed
issue_project_not_exist=ID does not exist or other errors
#ldap
ldap_url_is_null=LDAP address is empty
ldap_dn_is_null=LDAP binding DN is empty

View File

@ -163,6 +163,7 @@ id_required=ID必填
id_repeat_in_table=表格内ID重复
step_model_tip=步骤描述填写 STEP,文本描述请填写 TEXT (非必填)
case_status_not_exist=用例状态必须为未开始(Prepare)、进行中(Underway)、已完成(Completed)
issue_project_not_exist=ID不存在或其它错误
#ldap
ldap_url_is_null=LDAP地址为空
ldap_dn_is_null=LDAP绑定DN为空

View File

@ -163,6 +163,7 @@ id_required=ID必填
id_repeat_in_table=表格內ID重復
step_model_tip=步驟描述填寫 STEP,文本描述請填寫 TEXT (非必填)
case_status_not_exist=用例狀態必須為未開始Prepare、進行中Underway、已完成Completed
issue_project_not_exist=ID不存在或其它錯誤
#ldap
ldap_url_is_null=LDAP地址為空
ldap_dn_is_null=LDAP綁定DN為空

View File

@ -39,12 +39,17 @@
</el-form-item>
<el-form-item :label-width="labelWidth" :label="$t('project.tapd_id')" v-if="tapd">
<el-input v-model="form.tapdId" autocomplete="off"></el-input>
<el-button @click="check" type="primary" class="checkButton">{{ $t('test_track.issue.check_id_exist') }}</el-button>
</el-form-item>
<project-jira-config v-if="jira" :label-width="labelWidth" :form="form"/>
<project-jira-config v-if="jira" :label-width="labelWidth" :form="form">
<template #checkBtn>
<el-button @click="check" type="primary" class="checkButton">{{ $t('test_track.issue.check_id_exist') }}</el-button>
</template>
</project-jira-config>
<el-form-item :label-width="labelWidth" :label="$t('project.zentao_id')" v-if="zentao">
<el-input v-model="form.zentaoId" autocomplete="off"></el-input>
<el-button @click="check" type="primary" class="checkButton">{{ $t('test_track.issue.check_id_exist') }}</el-button>
<ms-instructions-icon effect="light">
<template>
禅道流程产品-项目 | 产品-迭代 | 产品-冲刺 | 项目-迭代 | 项目-冲刺 <br/><br/>
@ -186,6 +191,15 @@ export default {
this.createVisible = false;
},
methods: {
check() {
if (!this.form.id) {
this.$warning(this.$t("test_track.issue.save_project_first"));
return;
}
this.$post("/project/check/third/project", this.form, () => {
this.$success("OK");
});
},
getOptions() {
if (this.$refs.issueTemplate) {
this.$refs.issueTemplate.getTemplateOptions();
@ -309,4 +323,8 @@ pre {
.el-input, .el-textarea {
width: 80%;
}
.checkButton {
margin-left: 5px;
}
</style>

View File

@ -2,6 +2,7 @@
<div>
<el-form-item :label-width="labelWidth" :label="$t('project.jira_key')">
<el-input v-model="form.jiraKey" autocomplete="off" @blur="getIssueTypeOption"/>
<slot name="checkBtn"></slot>
<ms-instructions-icon effect="light">
<template>
<img class="jira-image" src="@/assets/jira-key.png"/>

View File

@ -2362,7 +2362,9 @@ export default {
update_third_party_bugs: "Update the defects of third-party platforms",
sync_bugs: "Synchronization Issue",
save_before_open_comment: "Please save issue before comment",
delete_tip: "Confirm Delete Issue"
delete_tip: "Confirm Delete Issue",
check_id_exist: "Check",
save_project_first: "Please save the project first"
},
report: {
name: "Test Plan Report",

View File

@ -2367,7 +2367,9 @@ export default {
update_third_party_bugs: "更新第三方平台的缺陷",
sync_bugs: "同步缺陷",
save_before_open_comment: "请先保存缺陷再添加评论",
delete_tip: "确认删除缺陷:"
delete_tip: "确认删除缺陷:",
check_id_exist: "检查",
save_project_first: "请先保存项目"
},
report: {
name: "测试计划报告",

View File

@ -2366,7 +2366,9 @@ export default {
update_third_party_bugs: "更新第三方平臺的缺陷",
sync_bugs: "同步缺陷",
save_before_open_comment: "請先保存缺陷再添加評論",
delete_tip: "確認刪除缺陷:"
delete_tip: "確認刪除缺陷:",
check_id_exist: "檢查",
save_project_first: "請先保存項目"
},
report: {
name: "測試計劃報告",