feat(测试跟踪): 缺陷管理MS同步禅道附件

--story=1008034 --user=宋昌昌 【Bug转需求】[缺陷管理]-github#9580-jira集成,缺陷模版使用 jira 缺陷模版,字段没有同步全 https://www.tapd.cn/55049933/s/1216936
This commit is contained in:
song-cc-rock 2022-08-02 12:44:04 +08:00 committed by jianxing
parent f3a134c16f
commit 018af2ff32
5 changed files with 133 additions and 17 deletions

View File

@ -4,15 +4,9 @@ import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import io.metersphere.base.domain.IssuesDao;
import io.metersphere.base.domain.IssuesExample;
import io.metersphere.base.domain.IssuesWithBLOBs;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.*;
import io.metersphere.base.domain.ext.CustomFieldResource;
import io.metersphere.commons.constants.AttachmentSyncType;
import io.metersphere.commons.constants.IssuesManagePlatform;
import io.metersphere.commons.constants.IssuesStatus;
import io.metersphere.commons.constants.ZentaoIssuePlatformStatus;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.dto.UserDTO;
@ -25,8 +19,10 @@ import io.metersphere.track.issue.domain.zentao.AddIssueResponse;
import io.metersphere.track.issue.domain.zentao.GetIssueResponse;
import io.metersphere.track.issue.domain.zentao.ZentaoBuild;
import io.metersphere.track.issue.domain.zentao.ZentaoConfig;
import io.metersphere.track.request.attachment.AttachmentRequest;
import io.metersphere.track.request.testcase.IssuesRequest;
import io.metersphere.track.request.testcase.IssuesUpdateRequest;
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;
@ -34,7 +30,6 @@ import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
@ -47,12 +42,13 @@ 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"
"bmp", "jpg", "png", "tif", "gif", "jpeg"
};
@ -226,6 +222,22 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
} else {
MSException.throwException("请确认该Zentao账号是否开启超级modle调用接口权限");
}
// 如果是复制新增, 同步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 = fileService.getFileAttachmentMetadataByFileId(attachmentId);
File file = new File(fileAttachmentMetadata.getFilePath() + File.separator + fileAttachmentMetadata.getName());
zentaoClient.uploadAttachment("bug", issuesRequest.getPlatformId(), file);
});
}
}
return issues;
}
@ -389,6 +401,7 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
customFieldMap.put(item.getId(), customFieldService.getCustomFieldResource(issue.getCustomFields()));
issue.setId(item.getId());
issuesMapper.updateByPrimaryKeySelective(issue);
syncZentaoIssueAttachments(issue);
});
customFieldIssuesService.batchEditFields(customFieldMap);
}
@ -543,9 +556,69 @@ public class ZentaoPlatform extends AbstractIssuePlatform {
@Override
public void syncIssuesAttachment(IssuesUpdateRequest issuesRequest, File file, AttachmentSyncType syncType) {
// TODO: 同步缺陷MS附件到禅道
if ("upload".equals(syncType.syncOperateType())) {
zentaoClient.uploadAttachment("bug", issuesRequest.getPlatformId(), file);
} else if ("delete".equals(syncType.syncOperateType())) {
JSONObject bugInfo = zentaoClient.getBugById(issuesRequest.getPlatformId());
JSONObject zenFiles = bugInfo.getJSONObject("files");
for (String fileId : zenFiles.keySet()) {
JSONObject fileInfo = zenFiles.getJSONObject(fileId);
if (file.getName().equals(fileInfo.getString("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());
JSONObject bugInfo = zentaoClient.getBugById(issue.getPlatformId());
JSONObject zenFiles = bugInfo.getJSONObject("files");
// 同步Jira中新的附件
if (zenFiles != null) {
for (String fileId : zenFiles.keySet()) {
JSONObject fileInfo = zenFiles.getJSONObject(fileId);
String filename = fileInfo.getString("title");
znetaoAttachmentsName.add(filename);
if (!msAttachmentsName.contains(filename)) {
try {
byte[] bytes = zentaoClient.getAttachmentBytes(fileId);
FileAttachmentMetadata fileAttachmentMetadata = fileService.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);
}
}
}
}
// 删除Jira中不存在的附件
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附件及关联数据
fileService.deleteAttachment(ids);
fileService.deleteFileAttachmentByIds(ids);
attachmentModuleRelationMapper.deleteByExample(example);
});
}
}
@Override
public List<PlatformStatusDTO> getTransitions(String issueKey) {
List<PlatformStatusDTO> platformStatusDTOS = new ArrayList<>();

View File

@ -9,13 +9,12 @@ import io.metersphere.commons.utils.UnicodeConvertUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.track.issue.domain.zentao.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
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.util.Map;
public abstract class ZentaoClient extends BaseClient {
@ -215,4 +214,38 @@ public abstract class ZentaoClient extends BaseClient {
}
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, objectType, 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();
}
}

View File

@ -15,7 +15,9 @@ public class ZentaoGetClient extends ZentaoClient {
private static final String STORY_GET="&module=story&methodName=getProductStories&params=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&t=json&zentaosid=";
private static final String FILE_UPLOAD="&module=file&methodName=saveUpload&params=objectType={1},objectID={2},zentaosid={3}";
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=(.*?)\"/>");
@ -45,6 +47,8 @@ public class ZentaoGetClient extends ZentaoClient {
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;
}

View File

@ -17,7 +17,9 @@ public class ZentaoPathInfoClient extends ZentaoClient {
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.json?zentaosid=";
private static final String FILE_UPLOAD = "/api-getModel-file-saveUpload-{1}-{2}.json?zentaosid={3}";
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}";
@ -45,6 +47,8 @@ public class ZentaoPathInfoClient extends ZentaoClient {
request.setBugList(getUrl(BUG_LIST_URL));
request.setCreateMetaData(getUrl(CREATE_META_DATA));
request.setProductGet(getUrl(PRODUCT_GET));
request.setFileDelete(getUrl(FILE_DELETE));
request.setFileDelete(getUrl(FILE_DOWNLOAD));
requestUrl = request;
}

View File

@ -20,6 +20,8 @@ public class RequestUrl {
private String userGet;
private String buildsGet;
private String fileUpload;
private String fileDelete;
private String fileDownload;
private String replaceImgUrl;
private String productGet;
private Pattern imgPattern;