fix(项目管理): 自定义字段消息通知不展示

--bug=1047046 --user=宋昌昌 【消息通知】缺陷管理的消息通知中自定义字段获取不到实际值 https://www.tapd.cn/55049933/s/1619144
This commit is contained in:
song-cc-rock 2024-11-28 18:25:07 +08:00 committed by 刘瑞斌
parent c654d22042
commit ea9c3c9a19
4 changed files with 105 additions and 141 deletions

View File

@ -6,7 +6,6 @@ import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.domain.ServiceIntegration;
import io.metersphere.system.schedule.BaseScheduleJob;
import io.metersphere.system.service.LicenseService;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
@ -14,15 +13,14 @@ import org.quartz.TriggerKey;
/**
* 缺陷同步定时任务
* @author song-cc-rock
*/
public class BugSyncJob extends BaseScheduleJob {
private final LicenseService licenseService;
private final BugSyncService bugSyncService;
private final ProjectApplicationService projectApplicationService;
public BugSyncJob() {
licenseService = CommonBeanFactory.getBean(LicenseService.class);
bugSyncService = CommonBeanFactory.getBean(BugSyncService.class);
projectApplicationService = CommonBeanFactory.getBean(ProjectApplicationService.class);
}
@ -49,11 +47,11 @@ public class BugSyncJob extends BaseScheduleJob {
boolean increment = projectApplicationService.isPlatformSyncMethodByIncrement(resourceId);
if (increment) {
// 增量同步
LogUtils.info("Incremental synchronization");
LogUtils.info("Incremental Synchronization");
bugSyncService.syncPlatformBugBySchedule(resourceId, userId);
} else {
// 全量同步
LogUtils.info("Full synchronization");
LogUtils.info("Full Synchronization");
bugSyncService.syncPlatformAllBugBySchedule(resourceId, userId);
}
} catch (Exception e) {

View File

@ -64,6 +64,9 @@ import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author song-cc-rock
*/
@Service
public class BugAttachmentService {
@ -270,7 +273,7 @@ public class BugAttachmentService {
}
}
// 删除Jira中不存在的附件
// 删除三方平台中不存在的附件
deleteSyncAttachmentFromMs(platformAttachmentSet, allBugFiles, bugId, projectId);
}
}

View File

@ -2,6 +2,7 @@ package io.metersphere.bug.service;
import io.metersphere.bug.dto.request.BugBatchRequest;
import io.metersphere.bug.dto.request.BugEditRequest;
import io.metersphere.bug.dto.response.BugCustomFieldDTO;
import io.metersphere.bug.dto.response.BugDTO;
import io.metersphere.plugin.sdk.util.PluginUtils;
import io.metersphere.sdk.util.BeanUtils;
@ -27,6 +28,7 @@ public class BugNoticeService {
public static final String CUSTOM_TITLE = "summary";
public static final String CUSTOM_STATUS = "status";
public static final String CUSTOM_HANDLE_USER = "handleUser";
public static final String EMPTY_MULTIPLE = "[]";
@Resource
private BugService bugService;
@ -57,13 +59,7 @@ public class BugNoticeService {
// 处理人 {从自定义字段中获取状态}
notice.setHandleUser(PluginUtils.parseArray(field.getText()).getFirst().toString());
} else {
// 其他自定义字段
OptionDTO fieldDTO = new OptionDTO();
fieldDTO.setId(field.getName());
if (StringUtils.isNotEmpty(field.getText()) && !StringUtils.equals(field.getText(), "[]")) {
fieldDTO.setName(field.getText());
}
fields.add(fieldDTO);
fields.add(buildNoticeOptionDTO(field));
}
});
notice.setFields(fields);
@ -75,6 +71,7 @@ public class BugNoticeService {
* 获取缺陷通知
* @param id 缺陷ID
*/
@SuppressWarnings("unused")
public BugNoticeDTO getNoticeById(String id) {
// 缺陷基础信息
BugDTO bugDTO = bugLogService.getOriginalValue(id);
@ -123,17 +120,26 @@ public class BugNoticeService {
// 自定义字段解析{name: value}
if (CollectionUtils.isNotEmpty(bugDTO.getCustomFields())) {
List<OptionDTO> fields = new ArrayList<>();
bugDTO.getCustomFields().forEach(field -> {
// 其他自定义字段
OptionDTO fieldDTO = new OptionDTO();
fieldDTO.setId(field.getName());
if (StringUtils.isNotEmpty(field.getText()) && !StringUtils.equals(field.getText(), "[]")) {
fieldDTO.setName(field.getText());
}
fields.add(fieldDTO);
});
bugDTO.getCustomFields().forEach(field -> fields.add(buildNoticeOptionDTO(field)));
notice.setFields(fields);
}
return notice;
}
/**
* 构建通知自定义字段
* @param field 缺陷自定义字段
* @return 通知自定义字段
*/
private OptionDTO buildNoticeOptionDTO(BugCustomFieldDTO field) {
// 封装通知自定义字段
OptionDTO option = new OptionDTO();
option.setId(field.getName());
if (StringUtils.isNotEmpty(field.getText()) && !StringUtils.equals(field.getText(), EMPTY_MULTIPLE)) {
option.setName(field.getText());
} else {
option.setName(field.getValue());
}
return option;
}
}

View File

@ -672,10 +672,11 @@ public class BugService {
BugMapper batchBugMapper = sqlSession.getMapper(BugMapper.class);
BugContentMapper batchBugContentMapper = sqlSession.getMapper(BugContentMapper.class);
List<BugLocalAttachment> picAttachmentsFromPlatform = new ArrayList<>();
// 批量更新缺陷
updateBugs.forEach(updateBug -> {
// 处理同步的BUG中的富文本图片
syncRichTextToMs(updateBug, platform);
picAttachmentsFromPlatform.addAll(syncRichTextPicToMs(updateBug, platform));
updateBug.setCreateUser(null);
Bug bug = new Bug();
BeanUtils.copyBean(bug, updateBug);
@ -708,6 +709,11 @@ public class BugService {
bugMapper.deleteByPrimaryKey(deleteBugId);
});
// 批量插入同步的三方缺陷富文本附件
if (CollectionUtils.isNotEmpty(picAttachmentsFromPlatform)) {
extBugLocalAttachmentMapper.batchInsert(picAttachmentsFromPlatform);
}
// 同步附件至MS
if (MapUtils.isNotEmpty(syncBugResult.getAttachmentMap())) {
bugAttachmentService.syncAttachmentToMs(platform, syncBugResult.getAttachmentMap(), project.getId());
@ -1539,56 +1545,66 @@ public class BugService {
/**
* 处理同步缺陷中的富文本图片
*
* @param updateBug 同步更新的缺陷
* @param syncBug 同步更新的缺陷
* @param platform 平台对象
*/
private void syncRichTextToMs(PlatformBugDTO updateBug, Platform platform) {
if (MapUtils.isNotEmpty(updateBug.getRichTextImageMap())) {
Map<String, String> richTextImageMap = updateBug.getRichTextImageMap();
// 同步第三方的富文本文件
richTextImageMap.keySet().forEach(key -> platform.getAttachmentContent(key, (in) -> {
if (in == null) {
return;
}
String fileId = IDGenerator.nextStr();
String fileName = updateBug.getPlatform() + "-" + richTextImageMap.get(key);
byte[] bytes;
try {
// 获取第三方平台附件流
bytes = in.readAllBytes();
// 第三方平台下载的图片默认不压缩
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(updateBug.getProjectId(), updateBug.getId(), fileId, fileName));
} catch (Exception e) {
throw new MSException(e.getMessage());
}
// 保存缺陷附件关系
BugLocalAttachment localAttachment = new BugLocalAttachment();
localAttachment.setId(IDGenerator.nextStr());
localAttachment.setBugId(updateBug.getId());
localAttachment.setFileId(fileId);
localAttachment.setFileName(fileName);
localAttachment.setSize((long) bytes.length);
localAttachment.setCreateTime(System.currentTimeMillis());
localAttachment.setCreateUser("admin");
localAttachment.setSource(BugAttachmentSourceType.RICH_TEXT.name());
bugLocalAttachmentMapper.insert(localAttachment);
// 替换富文本中的临时URL, 注意: 第三方的图片附件暂未存储在压缩目录, 因此不支持压缩访问
if (StringUtils.contains(updateBug.getDescription(), "alt=\"" + key + "\"")) {
updateBug.setDescription(updateBug.getDescription()
.replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + updateBug.getProjectId() + "/" + fileId + "/false\""));
if (updateBug.getPlatformDefaultTemplate()) {
// 来自富文本自定义字段
PlatformCustomFieldItemDTO descriptionField = updateBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getCustomData(), "description")).toList().getFirst();
descriptionField.setValue(updateBug.getDescription());
public List<BugLocalAttachment> syncRichTextPicToMs(PlatformBugDTO syncBug, Platform platform) {
List<BugLocalAttachment> picsFromPlatform = new ArrayList<>();
if (MapUtils.isNotEmpty(syncBug.getRichTextImageMap())) {
Map<String, String> richTextImageMap = syncBug.getRichTextImageMap();
try {
// 同步第三方的富文本文件
richTextImageMap.keySet().forEach(key -> platform.getAttachmentContent(key, (in) -> {
if (in == null) {
return;
}
} else {
// 来自富文本自定义字段
PlatformCustomFieldItemDTO richTextField = updateBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getType(), PlatformCustomFieldType.RICH_TEXT.name())
&& field.getValue() != null && StringUtils.contains(field.getValue().toString(), "alt=\"" + key + "\"")).toList().getFirst();
richTextField.setValue(richTextField.getValue().toString().replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + updateBug.getProjectId() + "/" + fileId + "/false\""));
}
}));
String fileId = IDGenerator.nextStr();
String fileName = syncBug.getPlatform() + "-" + richTextImageMap.get(key);
byte[] bytes;
try {
// 获取第三方平台附件流
bytes = in.readAllBytes();
// 第三方平台下载的图片默认不压缩
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(syncBug.getProjectId(), syncBug.getId(), fileId, fileName));
} catch (Exception e) {
throw new MSException(e.getMessage());
}
// 保存缺陷附件关系
BugLocalAttachment localAttachment = new BugLocalAttachment();
localAttachment.setId(IDGenerator.nextStr());
localAttachment.setBugId(syncBug.getId());
localAttachment.setFileId(fileId);
localAttachment.setFileName(fileName);
localAttachment.setSize((long) bytes.length);
localAttachment.setCreateTime(System.currentTimeMillis());
localAttachment.setCreateUser("admin");
localAttachment.setSource(BugAttachmentSourceType.RICH_TEXT.name());
picsFromPlatform.add(localAttachment);
// 替换富文本中的临时URL, 注意: 第三方的图片附件暂未存储在压缩目录, 因此不支持压缩访问
String tmpRichUrl = getPlatformTmpRichUrlOfKey(key);
if (StringUtils.isBlank(tmpRichUrl)) {
return;
}
if (StringUtils.contains(syncBug.getDescription(), tmpRichUrl)) {
syncBug.setDescription(syncBug.getDescription()
.replace(tmpRichUrl, "src=\"/bug/attachment/preview/md/" + syncBug.getProjectId() + "/" + fileId + "/false\""));
if (syncBug.getPlatformDefaultTemplate()) {
// 来自富文本自定义字段
PlatformCustomFieldItemDTO descriptionField = syncBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getCustomData(), "description")).toList().getFirst();
descriptionField.setValue(syncBug.getDescription());
}
} else {
// 来自富文本自定义字段
PlatformCustomFieldItemDTO richTextField = syncBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getType(), PlatformCustomFieldType.RICH_TEXT.name())
&& field.getValue() != null && StringUtils.contains(field.getValue().toString(), tmpRichUrl)).toList().getFirst();
richTextField.setValue(richTextField.getValue().toString().replace(tmpRichUrl, "src=\"/bug/attachment/preview/md/" + syncBug.getProjectId() + "/" + fileId + "/false\""));
}
}));
} catch (Exception e) {
LogUtils.warn("sync platform bug rich text image error : " + e.getMessage());
}
}
return picsFromPlatform;
}
@ -1790,10 +1806,7 @@ public class BugService {
BeanUtils.copyBean(bugPageRequest, request);
bugPageRequest.setUseTrash(false);
if (request.getCondition() != null) {
bugPageRequest.setCombine(request.getCondition().getCombine());
bugPageRequest.setFilter(request.getCondition().getFilter());
bugPageRequest.setSearchMode(request.getCondition().getSearchMode());
bugPageRequest.setKeyword(request.getCondition().getKeyword());
BeanUtils.copyBean(bugPageRequest, request.getCondition());
}
List<BugDTO> allBugs = extBugMapper.list(bugPageRequest, request.getSort());
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
@ -1821,10 +1834,7 @@ public class BugService {
BugPageRequest bugPageRequest = new BugPageRequest();
BeanUtils.copyBean(bugPageRequest, request);
if (request.getCondition() != null) {
bugPageRequest.setCombine(request.getCondition().getCombine());
bugPageRequest.setFilter(request.getCondition().getFilter());
bugPageRequest.setSearchMode(request.getCondition().getSearchMode());
bugPageRequest.setKeyword(request.getCondition().getKeyword());
BeanUtils.copyBean(bugPageRequest, request.getCondition());
}
List<String> ids = extBugMapper.getIdsByPageRequest(bugPageRequest);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
@ -1996,6 +2006,12 @@ public class BugService {
Map<String, String> needSyncApiFieldMap = new HashMap<>(12);
PlatformBugDTO platformBug = saveModel.getPlatformBug();
Bug originalBug = saveModel.getMsBug();
// 非平台默认模板时, 设置需要处理的字段
if (!platformBug.getPlatformDefaultTemplate()) {
List<TemplateCustomField> templateCustomFields = saveModel.getTemplateFieldMap().get(platformBug.getTemplateId());
needSyncApiFieldMap = templateCustomFields.stream().filter(field -> StringUtils.isNotBlank(field.getApiFieldId()))
.collect(Collectors.toMap(TemplateCustomField::getApiFieldId, TemplateCustomField::getFieldId));
}
// 设置缺陷基础信息
if (originalBug == null) {
// 新增
@ -2009,12 +2025,6 @@ public class BugService {
platformBug.setDeleteTime(platformBug.getCreateTime());
platformBug.setDeleted(false);
platformBug.setPos(atomicPos.getAndAdd(INTERVAL_POS));
// 非平台默认模板时, 设置需要处理的字段
if (!platformBug.getPlatformDefaultTemplate()) {
List<TemplateCustomFieldDTO> defaultTemplateCustomFields = saveModel.getMsDefaultTemplate().getCustomFields();
needSyncApiFieldMap = defaultTemplateCustomFields.stream().filter(field -> StringUtils.isNotBlank(field.getApiFieldId()))
.collect(Collectors.toMap(TemplateCustomFieldDTO::getApiFieldId, TemplateCustomFieldDTO::getFieldId));
}
} else {
// 更新
platformBug.setId(originalBug.getId());
@ -2029,68 +2039,11 @@ public class BugService {
platformBug.setPlatform(originalBug.getPlatform());
platformBug.setCreateUser(null);
platformBug.setPlatformDefaultTemplate(isPluginDefaultTemplate(platformBug.getTemplateId(), saveModel.getPluginDefaultTemplate()));
// 非平台默认模板时, 设置需要处理的字段
if (!platformBug.getPlatformDefaultTemplate()) {
List<TemplateCustomField> templateCustomFields = saveModel.getTemplateFieldMap().get(platformBug.getTemplateId());
needSyncApiFieldMap = templateCustomFields.stream().filter(field -> StringUtils.isNotBlank(field.getApiFieldId()))
.collect(Collectors.toMap(TemplateCustomField::getApiFieldId, TemplateCustomField::getFieldId));
}
}
Bug bug = new Bug();
BeanUtils.copyBean(bug, platformBug);
// 如果缺陷需要同步第三方的富文本文件
List<BugLocalAttachment> richTextAttachments = new ArrayList<>();
if (MapUtils.isNotEmpty(platformBug.getRichTextImageMap())) {
Map<String, String> richTextImageMap = platformBug.getRichTextImageMap();
// 同步第三方的富文本文件
try {
Platform platform = saveModel.getPlatform();
richTextImageMap.keySet().forEach(key -> platform.getAttachmentContent(key, (in) -> {
if (in == null) {
return;
}
String fileId = IDGenerator.nextStr();
// 第三方同步的文件名加上平台前缀, 防止同名
String fileName = saveModel.getPlatformName() + "-" + richTextImageMap.get(key);
byte[] bytes;
try {
// 获取第三方平台附件流, 并上传至Minio, 默认不压缩
bytes = in.readAllBytes();
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(platformBug.getProjectId(), platformBug.getId(), fileId, fileName));
} catch (Exception e) {
throw new MSException(e.getMessage());
}
// 保存缺陷附件关系
BugLocalAttachment localAttachment = new BugLocalAttachment();
localAttachment.setId(IDGenerator.nextStr());
localAttachment.setBugId(platformBug.getId());
localAttachment.setFileId(fileId);
localAttachment.setFileName(fileName);
localAttachment.setSize((long) bytes.length);
localAttachment.setCreateTime(System.currentTimeMillis());
localAttachment.setCreateUser("admin");
localAttachment.setSource(BugAttachmentSourceType.RICH_TEXT.name());
richTextAttachments.add(localAttachment);
// 替换富文本中的临时URL, 注意: 第三方的图片附件暂未存储在压缩目录, 因此不支持压缩访问
if (StringUtils.contains(platformBug.getDescription(), "alt=\"" + key + "\"")) {
platformBug.setDescription(platformBug.getDescription()
.replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + platformBug.getProjectId() + "/" + fileId + "/false\""));
if (platformBug.getPlatformDefaultTemplate()) {
// 来自富文本自定义字段
PlatformCustomFieldItemDTO descriptionField = platformBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getCustomData(), "description")).toList().getFirst();
descriptionField.setValue(platformBug.getDescription());
}
} else {
// 来自富文本自定义字段
PlatformCustomFieldItemDTO richTextField = platformBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getType(), PlatformCustomFieldType.RICH_TEXT.name())
&& field.getValue() != null && StringUtils.contains(field.getValue().toString(), "alt=\"" + key + "\"")).toList().getFirst();
richTextField.setValue(richTextField.getValue().toString().replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + platformBug.getProjectId() + "/" + fileId + "/false\""));
}
}));
} catch (Exception e) {
LogUtils.error("sync platform bug rich text image error : " + e.getMessage());
}
}
List<BugLocalAttachment> richTextAttachments = syncRichTextPicToMs(platformBug, saveModel.getPlatform());
BugContent bugContent = new BugContent();
bugContent.setBugId(platformBug.getId());
bugContent.setDescription(platformBug.getDescription());
@ -2143,4 +2096,8 @@ public class BugService {
LogUtils.error(e);
}
}
private String getPlatformTmpRichUrlOfKey(String key) {
return "alt=\"" + key + "\"";
}
}