diff --git a/framework/sdk-parent/frontend/src/components/personal/PersonRouter.vue b/framework/sdk-parent/frontend/src/components/personal/PersonRouter.vue
index ee62ecba6a..c8e37f4d7a 100644
--- a/framework/sdk-parent/frontend/src/components/personal/PersonRouter.vue
+++ b/framework/sdk-parent/frontend/src/components/personal/PersonRouter.vue
@@ -29,7 +29,7 @@
@@ -64,6 +64,7 @@ import {useUserStore} from "@/store";
import {handleAuth as _handleAuth, getUserInfo, getWsAndPj, updateInfo} from "../../api/user";
import PlatformAccountConfig from "./PlatformAccountConfig";
import {getPlatformAccountInfo} from "../../api/platform-plugin";
+import {ISSUE_PLATFORM_OPTION} from "../../utils/table-constants";
const userStore = useUserStore();
@@ -125,6 +126,9 @@ export default {
currentUser: () => {
return getCurrentUser();
},
+ showPlatformConfig(platform) {
+ return ISSUE_PLATFORM_OPTION.map(item => item.value).indexOf(platform) < 0;
+ },
handleAuth(type) {
let param = {...this.currentPlatformInfo};
if (type === 'Zentao') {
@@ -246,7 +250,8 @@ export default {
height: 40px;
line-height: 40px;
}
+
.el-form-item-class {
- margin-left:110px;
+ margin-left: 110px;
}
diff --git a/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/controller/XpackIssueController.java b/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/controller/XpackIssueController.java
deleted file mode 100644
index f08a5ae732..0000000000
--- a/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/controller/XpackIssueController.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package io.metersphere.xpack.track.controller;
-
-import io.metersphere.commons.utils.CommonBeanFactory;
-import io.metersphere.xpack.track.dto.IssueSyncRequest;
-import io.metersphere.xpack.track.service.XpackIssueService;
-import org.springframework.web.bind.annotation.*;
-
-@RestController
-@RequestMapping(value = "/xpack/issue")
-public class XpackIssueController {
-
- @PostMapping("/sync")
- public boolean getPlatformIssue(@RequestBody IssueSyncRequest request) {
- XpackIssueService xpackIssueService = CommonBeanFactory.getBean(XpackIssueService.class);
- return xpackIssueService.syncThirdPartyIssues(request);
- }
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/request/attachment/AttachmentRequest.java b/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/AttachmentRequest.java
similarity index 85%
rename from test-track/backend/src/main/java/io/metersphere/request/attachment/AttachmentRequest.java
rename to framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/AttachmentRequest.java
index 65305a0cb5..64edeb50c0 100644
--- a/test-track/backend/src/main/java/io/metersphere/request/attachment/AttachmentRequest.java
+++ b/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/AttachmentRequest.java
@@ -1,4 +1,4 @@
-package io.metersphere.request.attachment;
+package io.metersphere.xpack.track.dto;
import lombok.Data;
diff --git a/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/IssueSyncRequest.java b/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/IssueSyncRequest.java
index 5e425522ab..e5fd8b8339 100644
--- a/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/IssueSyncRequest.java
+++ b/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/IssueSyncRequest.java
@@ -2,6 +2,10 @@ package io.metersphere.xpack.track.dto;
import lombok.Data;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* @author songcc
*/
@@ -22,4 +26,8 @@ public class IssueSyncRequest {
* TRUE: 创建时间之前
*/
private boolean pre;
+
+ private String defaultCustomFields;
+
+ private Map> attachmentMap = new HashMap<>();
}
diff --git a/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/PlatformAttachment.java b/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/PlatformAttachment.java
new file mode 100644
index 0000000000..360d3373c2
--- /dev/null
+++ b/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/dto/PlatformAttachment.java
@@ -0,0 +1,11 @@
+package io.metersphere.xpack.track.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class PlatformAttachment {
+ private String fileName;
+ private String fileKey;
+}
diff --git a/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/service/XpackIssueService.java b/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/service/XpackIssueService.java
index b3ec508d46..5f5899fef3 100644
--- a/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/service/XpackIssueService.java
+++ b/framework/sdk-parent/xpack-interface/src/main/java/io/metersphere/xpack/track/service/XpackIssueService.java
@@ -1,10 +1,11 @@
package io.metersphere.xpack.track.service;
+import io.metersphere.base.domain.Project;
import io.metersphere.xpack.track.dto.IssueSyncRequest;
public interface XpackIssueService {
- boolean syncThirdPartyIssues(IssueSyncRequest request);
+ boolean syncThirdPartyIssues(Project project, IssueSyncRequest request);
void syncThirdPartyIssues();
}
diff --git a/test-track/backend/src/main/java/io/metersphere/controller/AttachmentController.java b/test-track/backend/src/main/java/io/metersphere/controller/AttachmentController.java
index 2f9e286e48..c29e9cb8c0 100644
--- a/test-track/backend/src/main/java/io/metersphere/controller/AttachmentController.java
+++ b/test-track/backend/src/main/java/io/metersphere/controller/AttachmentController.java
@@ -3,7 +3,7 @@ package io.metersphere.controller;
import io.metersphere.base.domain.FileAttachmentMetadata;
import io.metersphere.metadata.service.FileMetadataService;
import io.metersphere.request.attachment.AttachmentDumpRequest;
-import io.metersphere.request.attachment.AttachmentRequest;
+import io.metersphere.xpack.track.dto.AttachmentRequest;
import io.metersphere.service.AttachmentService;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
diff --git a/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java b/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java
index bdbbcc81c3..1f01593e26 100644
--- a/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java
+++ b/test-track/backend/src/main/java/io/metersphere/controller/IssuesController.java
@@ -25,10 +25,7 @@ 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.IssueTemplateDao;
-import io.metersphere.xpack.track.dto.IssuesDao;
-import io.metersphere.xpack.track.dto.PlatformStatusDTO;
-import io.metersphere.xpack.track.dto.PlatformUser;
+import io.metersphere.xpack.track.dto.*;
import io.metersphere.xpack.track.dto.request.IssuesRequest;
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
import org.apache.commons.collections.CollectionUtils;
@@ -164,10 +161,15 @@ public class IssuesController {
}
@GetMapping("/sync/{projectId}")
- public boolean getPlatformIssue(@PathVariable String projectId) {
+ public boolean syncThirdPartyIssues(@PathVariable String projectId) {
return issuesService.syncThirdPartyIssues(projectId);
}
+ @PostMapping("/sync/all")
+ public boolean syncThirdPartyAllIssues(@RequestBody IssueSyncRequest request) {
+ return issuesService.syncThirdPartyAllIssues(request);
+ }
+
@GetMapping("/sync/check/{projectId}")
public boolean checkSync(@PathVariable String projectId) {
return issuesService.checkSync(projectId);
diff --git a/test-track/backend/src/main/java/io/metersphere/service/AttachmentService.java b/test-track/backend/src/main/java/io/metersphere/service/AttachmentService.java
index f64d8ec27c..d8fc654552 100644
--- a/test-track/backend/src/main/java/io/metersphere/service/AttachmentService.java
+++ b/test-track/backend/src/main/java/io/metersphere/service/AttachmentService.java
@@ -13,7 +13,7 @@ import io.metersphere.i18n.Translator;
import io.metersphere.metadata.service.FileMetadataService;
import io.metersphere.metadata.utils.MetadataUtils;
import io.metersphere.platform.domain.SyncIssuesAttachmentRequest;
-import io.metersphere.request.attachment.AttachmentRequest;
+import io.metersphere.xpack.track.dto.AttachmentRequest;
import io.metersphere.service.issue.platform.IssueFactory;
import io.metersphere.xmind.utils.FileUtil;
import io.metersphere.xpack.track.dto.AttachmentSyncType;
diff --git a/test-track/backend/src/main/java/io/metersphere/service/CustomFieldIssuesService.java b/test-track/backend/src/main/java/io/metersphere/service/CustomFieldIssuesService.java
index b699332bd5..ca7b25bee6 100644
--- a/test-track/backend/src/main/java/io/metersphere/service/CustomFieldIssuesService.java
+++ b/test-track/backend/src/main/java/io/metersphere/service/CustomFieldIssuesService.java
@@ -6,6 +6,7 @@ import io.metersphere.base.domain.CustomFieldIssues;
import io.metersphere.base.domain.CustomFieldIssuesExample;
import io.metersphere.base.mapper.CustomFieldIssuesMapper;
import io.metersphere.base.mapper.ext.BaseCustomFieldResourceMapper;
+import io.metersphere.commons.utils.SubListUtil;
import io.metersphere.constants.SystemCustomField;
import io.metersphere.dto.CustomFieldDao;
import io.metersphere.dto.CustomFieldResourceDTO;
@@ -102,9 +103,19 @@ public class CustomFieldIssuesService extends CustomFieldResourceService {
}
}
}
- addList.forEach(l -> batchMapper.insert(TABLE_NAME, l));
- updateList.forEach(l -> batchMapper.updateByPrimaryKeySelective(TABLE_NAME, l));
- sqlSession.flushStatements();
+
+ int batchSize = 500;
+
+ SubListUtil.dealForSubList(addList, batchSize, (subList) -> {
+ subList.forEach(l -> batchMapper.insert(TABLE_NAME, (CustomFieldResourceDTO) l));
+ sqlSession.commit();
+ });
+
+ SubListUtil.dealForSubList(updateList, batchSize, (subList) -> {
+ subList.forEach(l -> batchMapper.updateByPrimaryKeySelective(TABLE_NAME, (CustomFieldResourceDTO) l));
+ sqlSession.commit();
+ });
+
if (sqlSession != null && sqlSessionFactory != null) {
SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java b/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java
index be099a7d07..dc8edb45c8 100644
--- a/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java
+++ b/test-track/backend/src/main/java/io/metersphere/service/IssuesService.java
@@ -38,8 +38,9 @@ import io.metersphere.plan.service.TestPlanTestCaseService;
import io.metersphere.plan.utils.TestPlanStatusCalculator;
import io.metersphere.platform.api.Platform;
import io.metersphere.platform.domain.*;
+import io.metersphere.platform.domain.PlatformAttachment;
import io.metersphere.request.IntegrationRequest;
-import io.metersphere.request.attachment.AttachmentRequest;
+import io.metersphere.xpack.track.dto.AttachmentRequest;
import io.metersphere.request.issues.IssueExportRequest;
import io.metersphere.request.issues.IssueImportRequest;
import io.metersphere.request.issues.PlatformIssueTypeRequest;
@@ -58,6 +59,7 @@ import io.metersphere.xpack.track.dto.*;
import io.metersphere.xpack.track.dto.request.IssuesRequest;
import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
import io.metersphere.xpack.track.issue.IssuesPlatform;
+import io.metersphere.xpack.track.service.XpackIssueService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
@@ -1005,7 +1007,7 @@ public class IssuesService {
request.setIssues(platformIssues);
request.setDefaultCustomFields(defaultCustomFields);
request.setProjectConfig(PlatformPluginService.getCompatibleProjectConfig(project));
- Platform platform = platformPluginService.getPlatform(project.getPlatform());
+ Platform platform = platformPluginService.getPlatform(project.getPlatform(), project.getWorkspaceId());
// 获取需要变更的缺陷
SyncIssuesResult syncIssuesResult = platform.syncIssues(request);
@@ -1047,61 +1049,125 @@ public class IssuesService {
}
}
- private void syncPluginIssueAttachment(Platform platform, SyncIssuesResult syncIssuesResult, AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper) {
+ private void syncPluginIssueAttachment(Platform platform, SyncIssuesResult syncIssuesResult,
+ AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper) {
Map> attachmentMap = syncIssuesResult.getAttachmentMap();
if (MapUtils.isNotEmpty(attachmentMap)) {
for (String issueId : attachmentMap.keySet()) {
// 查询我们平台的附件
Set jiraAttachmentSet = new HashSet<>();
- AttachmentRequest attachmentRequest = new AttachmentRequest();
- attachmentRequest.setBelongType(AttachmentType.ISSUE.type());
- attachmentRequest.setBelongId(issueId);
- List allMsAttachments = attachmentService.listMetadata(attachmentRequest);
+ List allMsAttachments = getIssueFileAttachmentMetadata(issueId);
Set attachmentsNameSet = allMsAttachments.stream()
.map(FileAttachmentMetadata::getName)
.collect(Collectors.toSet());
List syncAttachments = attachmentMap.get(issueId);
for (PlatformAttachment syncAttachment : syncAttachments) {
- if (!attachmentsNameSet.contains(syncAttachment.getFileName())) {
- jiraAttachmentSet.add(syncAttachment.getFileName());
- try {
- byte[] content = platform.getAttachmentContent(syncAttachment.getFileKey());
- if (content == null) {
- continue;
- }
- FileAttachmentMetadata fileAttachmentMetadata = attachmentService
- .saveAttachmentByBytes(content, AttachmentType.ISSUE.type(), issueId, syncAttachment.getFileName());
- AttachmentModuleRelation attachmentModuleRelation = new AttachmentModuleRelation();
- attachmentModuleRelation.setAttachmentId(fileAttachmentMetadata.getId());
- attachmentModuleRelation.setRelationId(issueId);
- attachmentModuleRelation.setRelationType(AttachmentType.ISSUE.type());
- batchAttachmentModuleRelationMapper.insert(attachmentModuleRelation);
- } catch (Exception e) {
- LogUtil.error(e);
- }
+ String fileName = syncAttachment.getFileName();
+ String fileKey = syncAttachment.getFileKey();
+ if (!attachmentsNameSet.contains(fileName)) {
+ jiraAttachmentSet.add(fileName);
+ saveAttachmentModuleRelation(platform, issueId, fileName, fileKey, batchAttachmentModuleRelationMapper);
}
+
}
// 删除Jira中不存在的附件
- if (CollectionUtils.isNotEmpty(allMsAttachments)) {
- List deleteMsAttachments = allMsAttachments.stream()
- .filter(msAttachment -> !jiraAttachmentSet.contains(msAttachment.getName()))
- .collect(Collectors.toList());
- deleteMsAttachments.forEach(fileAttachmentMetadata -> {
- List ids = List.of(fileAttachmentMetadata.getId());
- AttachmentModuleRelationExample example = new AttachmentModuleRelationExample();
- example.createCriteria().andAttachmentIdIn(ids).andRelationTypeEqualTo(AttachmentType.ISSUE.type());
- // 删除MS附件及关联数据
- attachmentService.deleteAttachmentByIds(ids);
- attachmentService.deleteFileAttachmentByIds(ids);
- batchAttachmentModuleRelationMapper.deleteByExample(example);
- });
- }
+ deleteSyncAttachment(batchAttachmentModuleRelationMapper, jiraAttachmentSet, allMsAttachments);
}
}
}
+ private void syncAllPluginIssueAttachment(Project project, IssueSyncRequest syncIssuesResult) {
+ // todo 所有平台改造完之后删除
+ if (!StringUtils.equals(project.getPlatform(), IssuesManagePlatform.Jira.name())) {
+ return;
+ }
+ SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
+ try {
+ AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper = sqlSession.getMapper(AttachmentModuleRelationMapper.class);
+ Platform platform = platformPluginService.getPlatform(project.getPlatform(), project.getWorkspaceId());
+ Map> attachmentMap = syncIssuesResult.getAttachmentMap();
+ if (MapUtils.isNotEmpty(attachmentMap)) {
+ for (String issueId : attachmentMap.keySet()) {
+ // 查询我们平台的附件
+ Set jiraAttachmentSet = new HashSet<>();
+ List allMsAttachments = getIssueFileAttachmentMetadata(issueId);
+ Set attachmentsNameSet = allMsAttachments.stream()
+ .map(FileAttachmentMetadata::getName)
+ .collect(Collectors.toSet());
+
+ List syncAttachments = attachmentMap.get(issueId);
+ for (io.metersphere.xpack.track.dto.PlatformAttachment syncAttachment : syncAttachments) {
+ String fileName = syncAttachment.getFileName();
+ String fileKey = syncAttachment.getFileKey();
+ if (!attachmentsNameSet.contains(fileName)) {
+ jiraAttachmentSet.add(fileName);
+ saveAttachmentModuleRelation(platform, issueId, fileName, fileKey, batchAttachmentModuleRelationMapper);
+ }
+
+ }
+
+ // 删除Jira中不存在的附件
+ deleteSyncAttachment(batchAttachmentModuleRelationMapper, jiraAttachmentSet, allMsAttachments);
+ }
+ }
+ } catch (Exception e) {
+ LogUtil.error(e);
+ } finally {
+ SqlSessionUtils.closeSqlSession(sqlSession, sqlSessionFactory);
+ }
+ }
+
+ private void deleteSyncAttachment(AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper,
+ Set jiraAttachmentSet,
+ List allMsAttachments) {
+ // 删除Jira中不存在的附件
+ if (CollectionUtils.isNotEmpty(allMsAttachments)) {
+ List deleteMsAttachments = allMsAttachments.stream()
+ .filter(msAttachment -> !jiraAttachmentSet.contains(msAttachment.getName()))
+ .collect(Collectors.toList());
+ deleteMsAttachments.forEach(fileAttachmentMetadata -> {
+ List ids = List.of(fileAttachmentMetadata.getId());
+ AttachmentModuleRelationExample example = new AttachmentModuleRelationExample();
+ example.createCriteria().andAttachmentIdIn(ids).andRelationTypeEqualTo(AttachmentType.ISSUE.type());
+ // 删除MS附件及关联数据
+ attachmentService.deleteAttachmentByIds(ids);
+ attachmentService.deleteFileAttachmentByIds(ids);
+ batchAttachmentModuleRelationMapper.deleteByExample(example);
+ });
+ }
+ }
+
+ private void saveAttachmentModuleRelation(Platform platform, String issueId,
+ String fileName, String fileKey,
+ AttachmentModuleRelationMapper batchAttachmentModuleRelationMapper) {
+ try {
+ byte[] content = platform.getAttachmentContent(fileKey);
+ if (content == null) {
+ return;
+ }
+ FileAttachmentMetadata fileAttachmentMetadata = attachmentService
+ .saveAttachmentByBytes(content, AttachmentType.ISSUE.type(), issueId, fileName);
+ AttachmentModuleRelation attachmentModuleRelation = new AttachmentModuleRelation();
+ attachmentModuleRelation.setAttachmentId(fileAttachmentMetadata.getId());
+ attachmentModuleRelation.setRelationId(issueId);
+ attachmentModuleRelation.setRelationType(AttachmentType.ISSUE.type());
+ batchAttachmentModuleRelationMapper.insert(attachmentModuleRelation);
+ } catch (Exception e) {
+ LogUtil.error(e);
+ }
+
+ }
+
+ private List getIssueFileAttachmentMetadata(String issueId) {
+ AttachmentRequest attachmentRequest = new AttachmentRequest();
+ attachmentRequest.setBelongType(AttachmentType.ISSUE.type());
+ attachmentRequest.setBelongId(issueId);
+ List allMsAttachments = attachmentService.listMetadata(attachmentRequest);
+ return allMsAttachments;
+ }
+
/**
* 获取默认的自定义字段的取值,同步之后更新成第三方平台的值
@@ -1407,9 +1473,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.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());
@@ -1755,4 +1818,37 @@ public class IssuesService {
return BooleanUtils.isTrue(project.getThirdPartTemplate())
&& platformPluginService.isThirdPartTemplateSupport(project.getPlatform());
}
+
+ public boolean syncThirdPartyAllIssues(IssueSyncRequest syncRequest) {
+ syncRequest.setProjectId(syncRequest.getProjectId());
+ XpackIssueService xpackIssueService = CommonBeanFactory.getBean(XpackIssueService.class);
+ if (StringUtils.isNotBlank(syncRequest.getProjectId())) {
+ // 获取当前项目执行同步缺陷Key
+ String syncValue = getSyncKey(syncRequest.getProjectId());
+ // 存在即正在同步中
+ if (StringUtils.isNotEmpty(syncValue)) {
+ return false;
+ }
+ // 不存在则设置Key, 设置过期时间, 执行完成后delete掉
+ setSyncKey(syncRequest.getProjectId());
+
+ try {
+ Project project = baseProjectService.getProjectById(syncRequest.getProjectId());
+
+ if (!isThirdPartTemplate(project)) {
+ syncRequest.setDefaultCustomFields(getDefaultCustomFields(syncRequest.getProjectId()));
+ }
+
+ xpackIssueService.syncThirdPartyIssues(project, syncRequest);
+
+ syncAllPluginIssueAttachment(project, syncRequest);
+ } catch (Exception e) {
+ LogUtil.error(e);
+ MSException.throwException(e);
+ } finally {
+ deleteSyncKey(syncRequest.getProjectId());
+ }
+ }
+ return true;
+ }
}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/TestCaseService.java b/test-track/backend/src/main/java/io/metersphere/service/TestCaseService.java
index bb856f1566..f07f00df80 100644
--- a/test-track/backend/src/main/java/io/metersphere/service/TestCaseService.java
+++ b/test-track/backend/src/main/java/io/metersphere/service/TestCaseService.java
@@ -35,7 +35,7 @@ import io.metersphere.plan.service.TestPlanTestCaseService;
import io.metersphere.request.OrderRequest;
import io.metersphere.request.ProjectVersionRequest;
import io.metersphere.request.ResetOrderRequest;
-import io.metersphere.request.attachment.AttachmentRequest;
+import io.metersphere.xpack.track.dto.AttachmentRequest;
import io.metersphere.request.member.QueryMemberRequest;
import io.metersphere.request.testcase.*;
import io.metersphere.service.issue.platform.IssueFactory;
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/client/JiraAbstractClient.java b/test-track/backend/src/main/java/io/metersphere/service/issue/client/JiraAbstractClient.java
deleted file mode 100644
index c037e2fbb6..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/client/JiraAbstractClient.java
+++ /dev/null
@@ -1,290 +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.i18n.Translator;
-import io.metersphere.service.issue.domain.jira.*;
-import io.metersphere.xpack.track.dto.JiraIssue;
-import io.metersphere.xpack.track.dto.JiraIssueListResponse;
-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 org.springframework.web.client.HttpClientErrorException;
-
-import java.io.File;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-public abstract class JiraAbstractClient extends BaseClient {
-
- protected String ENDPOINT;
-
- protected String PREFIX;
-
- protected String USER_NAME;
-
- protected String PASSWD;
-
- public JiraIssue getIssues(String issuesId) {
- LogUtil.info("getIssues: " + issuesId);
- ResponseEntity responseEntity;
- responseEntity = restTemplate.exchange(getBaseUrl() + "/issue/" + issuesId, HttpMethod.GET, getAuthHttpEntity(), String.class);
- return (JiraIssue) getResultForObject(JiraIssue.class, responseEntity);
- }
-
- public Map getCreateMetadata(String projectKey, String issueType) {
- String url = getBaseUrl() + "/issue/createmeta?projectKeys={1}&issuetypeIds={2}&expand=projects.issuetypes.fields";
- ResponseEntity response = null;
- Map fields = null;
- try {
- response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class, projectKey, issueType);
- } catch (Exception e) {
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- }
- try {
- fields = ((JiraCreateMetadataResponse) getResultForObject(JiraCreateMetadataResponse.class, response))
- .getProjects().get(0).getIssuetypes().get(0).getFields();
- } catch (Exception e) {
- MSException.throwException(Translator.get("issue_jira_info_error"));
- }
- fields.remove("project");
- fields.remove("issuetype");
- return fields;
- }
-
- public List getIssueType(String projectKey) {
- JiraIssueProject project = getProject(projectKey);
- String url = getUrl("/issuetype/project?projectId={0}");
- ResponseEntity response = null;
- try {
- response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class, project.getId());
- } catch (HttpClientErrorException e) {
- if (e.getRawStatusCode() == 404) { // Sass 的jira才有这个接口,报错则调用其他接口
- return this.getProject(projectKey).getIssueTypes();
- }
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- } catch (Exception e) {
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- }
- return (List) getResultForList(JiraIssueType.class, response);
- }
-
- public JiraIssueProject getProject(String projectKey) {
- String url = getUrl("/project/" + projectKey);
- ResponseEntity response = null;
- try {
- response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class);
- } catch (Exception e) {
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- }
- return (JiraIssueProject) getResultForObject(JiraIssueProject.class, response);
- }
-
- public List getAssignableUser(String projectKey) {
- String url = getBaseUrl() + "/user/assignable/search?project={1}&maxResults=" + 1000 + "&startAt=" + 0;
- ResponseEntity response = null;
- try {
- response = restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), String.class, projectKey);
- } catch (Exception e) {
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- }
- return (List) getResultForList(JiraUser.class, response);
- }
-
- public List getDemands(String projectKey, String issueType, int startAt, int maxResults) {
- String jql = getBaseUrl() + "/search?jql=project=" + projectKey + "+AND+issuetype=" + issueType
- + "&maxResults=" + maxResults + "&startAt=" + startAt + "&fields=summary,issuetype";
- ResponseEntity responseEntity = restTemplate.exchange(jql,
- HttpMethod.GET, getAuthHttpEntity(), String.class);
- Map jsonObject = JSON.parseMap(responseEntity.getBody());
- return (List) jsonObject.get("issues");
- }
-
- public List getFields() {
- ResponseEntity response = restTemplate.exchange(getBaseUrl() + "/field", HttpMethod.GET, getAuthHttpEntity(), String.class);
- return (List) getResultForList(JiraField.class, response);
- }
-
- public JiraAddIssueResponse addIssue(String body) {
- LogUtil.info("addIssue: " + body);
- HttpHeaders headers = getAuthHeader();
- headers.setContentType(MediaType.APPLICATION_JSON);
- HttpEntity requestEntity = new HttpEntity<>(body, headers);
- ResponseEntity response = null;
- try {
- response = restTemplate.exchange(getBaseUrl() + "/issue", HttpMethod.POST, requestEntity, String.class);
- } catch (Exception e) {
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- }
- return (JiraAddIssueResponse) getResultForObject(JiraAddIssueResponse.class, response);
- }
-
- public List getTransitions(String issueKey) {
- ResponseEntity response = restTemplate.exchange(getBaseUrl() + "/issue/{1}/transitions", HttpMethod.GET, getAuthHttpEntity(), String.class, issueKey);
- return ((JiraTransitionsResponse) getResultForObject(JiraTransitionsResponse.class, response)).getTransitions();
- }
-
- public void updateIssue(String id, String body) {
- LogUtil.info("addIssue: " + body);
- HttpHeaders headers = getAuthHeader();
- headers.setContentType(MediaType.APPLICATION_JSON);
- HttpEntity requestEntity = new HttpEntity<>(body, headers);
- try {
- restTemplate.exchange(getBaseUrl() + "/issue/" + id, HttpMethod.PUT, requestEntity, String.class);
- } catch (Exception e) {
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- }
- }
-
- public void deleteIssue(String id) {
- LogUtil.info("deleteIssue: " + id);
- try {
- restTemplate.exchange(getBaseUrl() + "/issue/" + id, HttpMethod.DELETE, getAuthHttpEntity(), String.class);
- } catch (HttpClientErrorException e) {
- if (e.getRawStatusCode() != 404) {// 404说明jira没有,可以直接删
- MSException.throwException(e.getMessage());
- }
- }
- }
-
- public void deleteAttachment(String id) {
- LogUtil.info("deleteAttachment: " + id);
- try {
- restTemplate.exchange(getBaseUrl() + "/attachment/" + id, HttpMethod.DELETE, getAuthHttpEntity(), String.class);
- } catch (HttpClientErrorException e) {
- if (e.getRawStatusCode() != 404) {// 404说明jira没有,可以直接删
- MSException.throwException(e.getMessage());
- }
- }
- }
-
-
- public void uploadAttachment(String issueKey, File file) {
- HttpHeaders authHeader = getAuthHeader();
- authHeader.add("X-Atlassian-Token", "no-check");
- authHeader.setContentType(MediaType.parseMediaType("multipart/form-data; charset=UTF-8"));
-
- MultiValueMap paramMap = new LinkedMultiValueMap<>();
- FileSystemResource fileResource = new FileSystemResource(file);
- paramMap.add("file", fileResource);
- HttpEntity> requestEntity = new HttpEntity<>(paramMap, authHeader);
- ResponseEntity response = null;
- try {
- response = restTemplate.exchange(getBaseUrl() + "/issue/" + issueKey + "/attachments", HttpMethod.POST, requestEntity, String.class);
- } catch (Exception e) {
- LogUtil.error(e.getMessage(), e);
- }
- System.out.println(response);
- }
-
- public void auth() {
- ResponseEntity response = null;
- try {
- response = restTemplate.exchange(getBaseUrl() + "/myself", HttpMethod.GET, getAuthHttpEntity(), String.class);
- if (StringUtils.isBlank(response.getBody()) || (StringUtils.isNotBlank(response.getBody()) && !response.getBody().startsWith("{\"self\""))) {
- MSException.throwException(Translator.get("jira_auth_url_error"));
- }
- } catch (HttpClientErrorException e) {
- if (e.getRawStatusCode() == 401) {
- MSException.throwException(Translator.get("jira_auth_error"));
- } else {
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- }
- } catch (Exception e) {
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- }
- }
-
- protected HttpEntity getAuthHttpEntity() {
- return new HttpEntity<>(getAuthHeader());
- }
-
- protected HttpHeaders getAuthHeader() {
- return getBasicHttpHeaders(USER_NAME, PASSWD);
- }
-
- protected HttpHeaders getAuthJsonHeader() {
- HttpHeaders headers = getAuthHeader();
- headers.setContentType(MediaType.APPLICATION_JSON);
- return headers;
- }
-
- protected String getBaseUrl() {
- return ENDPOINT + PREFIX;
- }
-
- protected String getUrl(String path) {
- return getBaseUrl() + path;
- }
-
- public void setConfig(JiraConfig config) {
- if (config == null) {
- MSException.throwException("config is null");
- }
- String url = config.getUrl();
-
- if (StringUtils.isNotBlank(url) && url.endsWith("/")) {
- url = url.substring(0, url.length() - 1);
- }
- ENDPOINT = url;
- USER_NAME = config.getAccount();
- PASSWD = config.getPassword();
- }
-
- public JiraIssueListResponse getProjectIssues(Integer startAt, Integer maxResults, String projectKey, String issueType) {
- return getProjectIssues(startAt, maxResults, projectKey, issueType, null);
- }
-
- public JiraIssueListResponse getProjectIssues(Integer startAt, Integer maxResults, String projectKey, String issueType, String fields) {
- ResponseEntity responseEntity;
- String url = getBaseUrl() + "/search?startAt={1}&maxResults={2}&jql=project={3}+AND+issuetype={4}";
- if (StringUtils.isNotBlank(fields)) {
- url = url + "&fields=" + fields;
- }
- responseEntity = restTemplate.exchange(url,
- HttpMethod.GET, getAuthHttpEntity(), String.class, startAt, maxResults, projectKey, issueType);
- return (JiraIssueListResponse)getResultForObject(JiraIssueListResponse.class, responseEntity);
- }
-
- public byte[] getAttachmentContent(String url) {
- ResponseEntity responseEntity;
- responseEntity = restTemplate.exchange(url,
- HttpMethod.GET, getAuthHttpEntity(), byte[].class);
- return responseEntity.getBody();
- }
-
- public JiraIssueListResponse getProjectIssuesAttachment(Integer startAt, Integer maxResults, String projectKey, String issueType) {
- return getProjectIssues(startAt, maxResults, projectKey, issueType, "attachment");
-
- }
- public void setTransitions(String jiraKey, JiraTransitionsResponse.Transitions transitions) {
- LogUtil.info("setTransitions: " + transitions);
- Map jsonObject = new LinkedHashMap();
- jsonObject.put("transition", transitions);
- HttpEntity requestEntity = new HttpEntity<>(JSON.toJSONString(jsonObject), getAuthJsonHeader());
- try {
- restTemplate.exchange(getBaseUrl() + "/issue/{1}/transitions", HttpMethod.POST, requestEntity, String.class, jiraKey);
- } catch (Exception e) {
- LogUtil.error(e.getMessage(), e);
- MSException.throwException(e.getMessage());
- }
- }
-
- public ResponseEntity proxyForGet(String url, Class responseEntityClazz) {
- LogUtil.info("jira proxyForGet: " + url);
- return restTemplate.exchange(url, HttpMethod.GET, getAuthHttpEntity(), responseEntityClazz);
- }
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/client/JiraClientV2.java b/test-track/backend/src/main/java/io/metersphere/service/issue/client/JiraClientV2.java
deleted file mode 100644
index b815ddab68..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/client/JiraClientV2.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package io.metersphere.service.issue.client;
-
-import org.springframework.stereotype.Component;
-
-@Component
-public class JiraClientV2 extends JiraAbstractClient {
- {
- PREFIX = "/rest/api/2";
- }
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/client/JiraClientV3.java b/test-track/backend/src/main/java/io/metersphere/service/issue/client/JiraClientV3.java
deleted file mode 100644
index ac8439495a..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/client/JiraClientV3.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package io.metersphere.service.issue.client;
-
-public class JiraClientV3 extends JiraAbstractClient {
- {
- PREFIX = "/rest/api/3";
- }
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraAddIssueResponse.java b/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraAddIssueResponse.java
deleted file mode 100644
index c84a65a252..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraAddIssueResponse.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.metersphere.service.issue.domain.jira;
-
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-public class JiraAddIssueResponse {
- private String id;
- private String key;
- private String self;
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraConfig.java b/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraConfig.java
deleted file mode 100644
index 1577bfde81..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraConfig.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package io.metersphere.service.issue.domain.jira;
-
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-public class JiraConfig {
- private String account;
- private String password;
- private String url;
- private String issuetype;
- private String storytype;
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraCreateMetadataResponse.java b/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraCreateMetadataResponse.java
deleted file mode 100644
index 9b767a82ff..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraCreateMetadataResponse.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package io.metersphere.service.issue.domain.jira;
-
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.List;
-import java.util.Map;
-
-@Setter
-@Getter
-public class JiraCreateMetadataResponse {
- private List projects;
-
- @Setter
- @Getter
- public static class Projects {
- private List issuetypes;
- }
-
- @Setter
- @Getter
- public static class Issuetypes {
- private Map fields;
- }
-
- @Setter
- @Getter
- public static class Field {
- private boolean required;
- private Schema schema;
- private String name;
- private String key;
- private String autoCompleteUrl;
- private boolean hasDefaultValue;
- private Object defaultValue;
- private List allowedValues;
- }
-
- @Setter
- @Getter
- public static class Schema {
- private String type;
- private String items;
- private String custom;
- private int customId;
- }
-
- @Setter
- @Getter
- public static class AllowedValues {
- private String self;
- private String id;
- private String description;
- private String name;
- private String value;
- private boolean subtask;
- private int avatarId;
- private int hierarchyLevel;
- private List children;
- }
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraField.java b/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraField.java
deleted file mode 100644
index f1cbe3e9ba..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraField.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package io.metersphere.service.issue.domain.jira;
-
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-public class JiraField {
-
- private String id;
- private String key;
- private String name;
- private boolean custom;
-// private boolean orderable;
-// private boolean navigable;
-// private boolean searchable;
-// private List clauseNames;
-// private Schema schema;
-//
-// @Getter
-// @Setter
-// public class Schema {
-// private String type;
-// private String system;
-// }
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraIssueDescriptionV3.java b/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraIssueDescriptionV3.java
deleted file mode 100644
index 87e46a4686..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraIssueDescriptionV3.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package io.metersphere.service.issue.domain.jira;
-
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@Data
-@NoArgsConstructor
-public class JiraIssueDescriptionV3 {
- private String type;
- private int version;
- private List content;
-
- public JiraIssueDescriptionV3(String text) {
- List list = new ArrayList<>();
- Content content = new Content(text);
- list.add(content);
- this.type = "doc";
- this.version = 1;
- this.content = list;
- }
-
- @Data
- @NoArgsConstructor
- public class Content {
- private String type;
- private List content;
-
- public Content(String text) {
- List list = new ArrayList<>();
- ContentInfo content = new ContentInfo(text);
- list.add(content);
- this.type = "paragraph";
- this.content = list;
- }
- }
-
- @Data
- @NoArgsConstructor
- public class ContentInfo {
- private String text;
- private String type;
-
- public ContentInfo(String text) {
- this.text = text;
- this.type = "text";
- }
-
- }
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraIssueProject.java b/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraIssueProject.java
deleted file mode 100644
index 372ff71fb2..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraIssueProject.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.metersphere.service.issue.domain.jira;
-
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.List;
-
-@Getter
-@Setter
-public class JiraIssueProject {
- private String id;
- private String name;
- private String key;
- private List issueTypes;
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraIssueType.java b/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraIssueType.java
deleted file mode 100644
index d50d0bee65..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraIssueType.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.metersphere.service.issue.domain.jira;
-
-import lombok.Getter;
-import lombok.Setter;
-
-@Getter
-@Setter
-public class JiraIssueType {
- private String id;
- private String name;
- private String untranslatedName;
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraTransitionsResponse.java b/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraTransitionsResponse.java
deleted file mode 100644
index 9725ed720e..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraTransitionsResponse.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package io.metersphere.service.issue.domain.jira;
-
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.List;
-
-@Getter
-@Setter
-public class JiraTransitionsResponse {
-
- private String expand;
- private List transitions;
-
- @Getter
- @Setter
- public static class Transitions {
- private String id;
- private String name;
- private To to;
- private Boolean hasScreen;
- private Boolean isGlobal;
- private Boolean isInitial;
- private Boolean isAvailable;
- private Boolean isConditional;
- private Boolean isLooped;
-
- }
-
- @Getter
- @Setter
- public static class To {
- private String self;
- private String description;
- private String iconUrl;
- private String name;
- private String id;
- private StatusCategory statusCategory;
- }
-
- @Getter
- @Setter
- public static class StatusCategory {
- private String self;
- private int id;
- private String key;
- private String colorName;
- private String name;
- }
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraUser.java b/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraUser.java
deleted file mode 100644
index 2627bd1ece..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/domain/jira/JiraUser.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.metersphere.service.issue.domain.jira;
-
-import lombok.Getter;
-import lombok.Setter;
-
-@Setter
-@Getter
-public class JiraUser {
- private String accountId;
- private String key;
- private String name;
- private String displayName;
- private String emailAddress;
- private Boolean active;
-}
diff --git a/test-track/backend/src/main/java/io/metersphere/service/issue/platform/JiraPlatform.java b/test-track/backend/src/main/java/io/metersphere/service/issue/platform/JiraPlatform.java
deleted file mode 100644
index e0d8ed9cbc..0000000000
--- a/test-track/backend/src/main/java/io/metersphere/service/issue/platform/JiraPlatform.java
+++ /dev/null
@@ -1,1030 +0,0 @@
-package io.metersphere.service.issue.platform;
-
-import io.metersphere.base.domain.*;
-import io.metersphere.commons.constants.CustomFieldType;
-import io.metersphere.commons.constants.IssuesManagePlatform;
-import io.metersphere.commons.constants.IssuesStatus;
-import io.metersphere.commons.exception.MSException;
-import io.metersphere.commons.utils.CommonBeanFactory;
-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.request.attachment.AttachmentRequest;
-import io.metersphere.xpack.track.dto.*;
-import io.metersphere.xpack.track.dto.request.IssuesRequest;
-import io.metersphere.xpack.track.dto.request.IssuesUpdateRequest;
-import io.metersphere.service.issue.client.JiraClientV2;
-import io.metersphere.service.IssuesService;
-import io.metersphere.service.issue.domain.ProjectIssueConfig;
-import io.metersphere.service.issue.domain.jira.*;
-import org.apache.commons.collections.CollectionUtils;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang3.ObjectUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.client.HttpClientErrorException;
-
-import java.io.File;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import java.text.SimpleDateFormat;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
-public class JiraPlatform extends AbstractIssuePlatform {
-
- protected JiraClientV2 jiraClientV2;
- protected SimpleDateFormat sdfWithZone = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
-
- protected Boolean isSass = false;
-
- public JiraPlatform(IssuesRequest issuesRequest) {
- super(issuesRequest);
- this.key = IssuesManagePlatform.Jira.name();
- jiraClientV2 = new JiraClientV2();
- setConfig();
- }
-
- // xpack 反射调用
- public JiraClientV2 getJiraClientV2() {
- return jiraClientV2;
- }
-
- public void setThirdPartTemplate() {
- this.isThirdPartTemplate = true;
- }
-
- @Override
- public List getIssue(IssuesRequest issuesRequest) {
- issuesRequest.setPlatform(key);
- List issues;
- if (StringUtils.isNotBlank(issuesRequest.getProjectId())) {
- issues = extIssuesMapper.getIssues(issuesRequest);
- } else {
- issues = extIssuesMapper.getIssuesByCaseId(issuesRequest);
- }
- return issues;
- }
-
- public IssuesWithBLOBs getUpdateIssue(JiraIssue jiraIssue) {
- return getUpdateIssue(null, jiraIssue);
- }
-
- public IssuesWithBLOBs getUpdateIssue(IssuesWithBLOBs issue, JiraIssue jiraIssue) {
- try {
- if (issue == null) {
- issue = new IssuesWithBLOBs();
- issue.setCustomFields(defaultCustomFields);
- } else {
- mergeCustomField(issue, defaultCustomFields);
- }
-
- Map fields = jiraIssue.getFields();
- String status = getStatus(fields);
-
- Map fileContentMap = getContextMap((List) fields.get("attachment"));
-
- // 先转换下desc的图片
- String description = dealWithDescription(Optional.ofNullable(fields.get("description")).orElse("").toString(), fileContentMap);
- fields.put("description", description);
- CustomFieldItemDTO descItem = null;
- List customFieldItems = syncIssueCustomFieldList(issue.getCustomFields(), jiraIssue.getFields());
-
- // 其他自定义里有富文本框的也转换下图片
- for (CustomFieldItemDTO item : customFieldItems) {
- if (StringUtils.equals("description", item.getId())) {
- // desc转过了,跳过
- descItem = item;
- } else {
- if (StringUtils.equals(CustomFieldType.RICH_TEXT.getValue(), item.getType())) {
- item.setValue(dealWithDescription((String) item.getValue(), fileContentMap));
- }
- }
- }
-
- Map assignee = (Map) fields.get("assignee");
- issue.setTitle(fields.get("summary").toString());
- issue.setLastmodify(assignee == null ? "" : assignee.get("displayName").toString());
- issue.setDescription(description);
- issue.setPlatformStatus(status);
- issue.setPlatform(key);
- issue.setCustomFields(JSON.toJSONString(customFieldItems));
- try {
- issue.setCreateTime(sdfWithZone.parse((String) fields.get("created")).getTime());
- issue.setUpdateTime(sdfWithZone.parse((String) fields.get("updated")).getTime());
- } catch (Exception e) {
- LogUtil.error(e);
- }
- return issue;
- } catch (Exception e) {
- LogUtil.error(e);
- MSException.throwException(e);
- return null;
- }
- }
-
- private String dealWithDescription(String description, Map fileContentMap) {
- if (StringUtils.isBlank(description)) {
- return description;
- }
-
- description = description.replaceAll("!image", "\n!image");
- String[] splitStrs = description.split("\\n");
- for (int j = 0; j < splitStrs.length; j++) {
- String splitStr = splitStrs[j];
- if (StringUtils.isNotEmpty(splitStr)) {
- List keys = fileContentMap.keySet().stream().filter(key -> splitStr.contains(key)).collect(Collectors.toList());
- if (CollectionUtils.isNotEmpty(keys)) {
- description = description.replace(splitStr, fileContentMap.get(keys.get(0)));
- fileContentMap.remove(keys.get(0));
- } else {
- if (splitStr.contains("MS附件:")) {
- // 解析标签内容
- String name = getHyperLinkPathForImg("\\!\\[(.*?)\\]", StringEscapeUtils.unescapeJava(splitStr));
- String path = getHyperLinkPathForImg("\\|(.*?)\\)", splitStr);
- path = "/resource/md/get/url?platform=Jira&url=" + URLEncoder.encode(path, StandardCharsets.UTF_8);
-
- // 解析标签内容为图片超链接格式,进行替换
- description = description.replace(splitStr, "\n\n![" + name + "](" + path + ")");
- }
- description = description.replace(splitStr, StringEscapeUtils.unescapeJava(splitStr.replace("MS附件:", "")));
- }
- }
- }
- return description;
- }
-
- private String appendMoreImage(String description, Map fileContentMap) {
- for (String key: fileContentMap.keySet()) {
- // 同步jira上传的附件
- description += StringUtils.LF + fileContentMap.get(key);
- }
- return description;
- }
-
- private Map getContextMap(List attachments) {
- // 附件处理
- Map fileContentMap = new HashMap<>();
- if (CollectionUtils.isNotEmpty(attachments)) {
- for (int i = 0; i < attachments.size(); i++) {
- Map attachment = (Map) attachments.get(i);
- String filename = attachment.get("filename").toString();
- String content = attachment.get("content").toString();
- content = "/resource/md/get/url?platform=Jira&url=" + URLEncoder.encode(content, StandardCharsets.UTF_8);
-
- if (StringUtils.contains(attachment.get("mimeType").toString(), "image")) {
- String contentUrl = "![" + filename + "](" + content + ")";
- fileContentMap.put(filename, contentUrl);
- } else {
- String contentUrl = "附件[" + filename + "]下载地址:" + content;
- fileContentMap.put(filename, contentUrl);
- }
- }
- }
- return fileContentMap;
- }
-
- private String getStatus(Map fields) {
- Map statusObj = (Map) fields.get("status");
- if (statusObj != null) {
- Map statusCategory = (Map) statusObj.get("statusCategory");
- return statusObj.get("name").toString() == null ? statusCategory.get("name").toString() : statusObj.get("name").toString();
- }
- return "";
- }
-
- @Override
- public List getDemandList(String projectId) {
- List list = new ArrayList<>();
- Project project = getProject();
- int maxResults = 50, startAt = 0;
- List demands;
- do {
- demands = jiraClientV2.getDemands(project.getJiraKey(), getStoryType(project.getIssueConfig()), startAt, maxResults);
- for (int i = 0; i < demands.size(); i++) {
- Map o = (Map) demands.get(i);
- String issueKey = o.get("key").toString();
- Map fields = (Map) o.get("fields");
- String summary = fields.get("summary").toString();
- DemandDTO demandDTO = new DemandDTO();
- demandDTO.setName(summary);
- demandDTO.setId(issueKey);
- demandDTO.setPlatform(key);
- list.add(demandDTO);
- }
- startAt += maxResults;
- } while (demands.size() >= maxResults);
- return list;
- }
-
- private void validateConfig(JiraConfig config) {
- jiraClientV2.setConfig(config);
- if (config == null) {
- MSException.throwException("jira config is null");
- }
- }
-
- public List getIssueTypes(String jiraKey) {
- return jiraClientV2.getIssueType(jiraKey);
- }
-
- @Override
- public IssuesWithBLOBs addIssue(IssuesUpdateRequest issuesRequest) {
-
- setUserConfig();
- Project project = getProject();
-
- Map addJiraIssueParam = buildUpdateParam(issuesRequest, getIssueType(project.getIssueConfig()), project.getJiraKey());
- JiraAddIssueResponse result = jiraClientV2.addIssue(JSON.toJSONString(addJiraIssueParam));
- JiraIssue issues = jiraClientV2.getIssues(result.getId());
-
- // 上传富文本中的图片作为附件
- List imageFiles = getImageFiles(issuesRequest);
- imageFiles.forEach(img -> jiraClientV2.uploadAttachment(result.getKey(), img));
-
- String status = getStatus(issues.getFields());
- issuesRequest.setPlatformStatus(status);
-
- issuesRequest.setPlatformId(result.getKey());
- issuesRequest.setId(UUID.randomUUID().toString());
-
- // 插入缺陷表
- IssuesWithBLOBs res = insertIssues(issuesRequest);
-
- // 用例与第三方缺陷平台中的缺陷关联
- handleTestCaseIssues(issuesRequest);
-
- // 如果是复制新增, 同步MS附件到Jira
- if (StringUtils.isNotEmpty(issuesRequest.getCopyIssueId())) {
- AttachmentRequest request = new AttachmentRequest();
- request.setBelongId(issuesRequest.getCopyIssueId());
- request.setBelongType(AttachmentType.ISSUE.type());
- List attachmentIds = attachmentService.getAttachmentIdsByParam(request);
- if (CollectionUtils.isNotEmpty(attachmentIds)) {
- attachmentIds.forEach(attachmentId -> {
- FileAttachmentMetadata fileAttachmentMetadata = attachmentService.getFileAttachmentMetadataByFileId(attachmentId);
- File file = new File(fileAttachmentMetadata.getFilePath() + "/" + fileAttachmentMetadata.getName());
- jiraClientV2.uploadAttachment(result.getKey(), file);
- });
- }
- }
-
- return res;
- }
-
- public Project getProject() {
- return super.getProject(this.projectId, Project::getJiraKey);
- }
-
- private List getImageFiles(IssuesUpdateRequest issuesRequest) {
- List files = new ArrayList<>();
- List customFields = issuesRequest.getRequestFields();
- customFields.forEach(item -> {
- String fieldName = item.getCustomData();
- if (StringUtils.isNotBlank(fieldName)) {
- if (item.getValue() != null) {
- if (StringUtils.isNotBlank(item.getType())) {
- if (StringUtils.equalsAny(item.getType(), "richText")) {
- files.addAll(getImageFiles(item.getValue().toString()));
- }
- }
- }
- }
- });
- return files;
- }
-
- /**
- * 参数比较特殊,需要特别处理
- * @param fields
- */
- private void setSpecialParam(Map fields) {
- Project project = getProject();
- try {
- Map createMetadata = jiraClientV2.getCreateMetadata(project.getJiraKey(), getIssueType(project.getIssueConfig()));
- List userOptions = jiraClientV2.getAssignableUser(project.getJiraKey());
-
- Boolean isUserKey = false;
- if (CollectionUtils.isNotEmpty(userOptions) && StringUtils.isBlank(userOptions.get(0).getAccountId())) {
- isUserKey = true;
- }
-
- for (String key : createMetadata.keySet()) {
- JiraCreateMetadataResponse.Field item = createMetadata.get(key);
- JiraCreateMetadataResponse.Schema schema = item.getSchema();
- if (schema == null) {
- continue;
- }
- if (schema.getCustom() != null && schema.getCustom().endsWith("sprint")) {
- try {
- Map field = (Map) fields.get(key);
- // sprint 传参数比较特殊,需要要传数值
- fields.put(key, (Integer) field.get("id"));
- } catch (Exception e) {}
- }
- if (isUserKey) {
- if (schema.getType() != null && schema.getType().endsWith("user")) {
- Map field = (Map) fields.get(key);
- // 如果不是用户ID,则是用户的key,参数调整为key
- Map newField = new LinkedHashMap<>();
- newField.put("name", field.get("id").toString());
- fields.put(key, newField);
- }
- if (schema.getCustom() != null && schema.getCustom().endsWith("multiuserpicker")) { // 多选用户列表
- try {
- List