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

View File

@ -64,6 +64,9 @@ import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
/**
* @author song-cc-rock
*/
@Service @Service
public class BugAttachmentService { public class BugAttachmentService {
@ -270,7 +273,7 @@ public class BugAttachmentService {
} }
} }
// 删除Jira中不存在的附件 // 删除三方平台中不存在的附件
deleteSyncAttachmentFromMs(platformAttachmentSet, allBugFiles, bugId, projectId); 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.BugBatchRequest;
import io.metersphere.bug.dto.request.BugEditRequest; import io.metersphere.bug.dto.request.BugEditRequest;
import io.metersphere.bug.dto.response.BugCustomFieldDTO;
import io.metersphere.bug.dto.response.BugDTO; import io.metersphere.bug.dto.response.BugDTO;
import io.metersphere.plugin.sdk.util.PluginUtils; import io.metersphere.plugin.sdk.util.PluginUtils;
import io.metersphere.sdk.util.BeanUtils; 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_TITLE = "summary";
public static final String CUSTOM_STATUS = "status"; public static final String CUSTOM_STATUS = "status";
public static final String CUSTOM_HANDLE_USER = "handleUser"; public static final String CUSTOM_HANDLE_USER = "handleUser";
public static final String EMPTY_MULTIPLE = "[]";
@Resource @Resource
private BugService bugService; private BugService bugService;
@ -57,13 +59,7 @@ public class BugNoticeService {
// 处理人 {从自定义字段中获取状态} // 处理人 {从自定义字段中获取状态}
notice.setHandleUser(PluginUtils.parseArray(field.getText()).getFirst().toString()); notice.setHandleUser(PluginUtils.parseArray(field.getText()).getFirst().toString());
} else { } else {
// 其他自定义字段 fields.add(buildNoticeOptionDTO(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);
} }
}); });
notice.setFields(fields); notice.setFields(fields);
@ -75,6 +71,7 @@ public class BugNoticeService {
* 获取缺陷通知 * 获取缺陷通知
* @param id 缺陷ID * @param id 缺陷ID
*/ */
@SuppressWarnings("unused")
public BugNoticeDTO getNoticeById(String id) { public BugNoticeDTO getNoticeById(String id) {
// 缺陷基础信息 // 缺陷基础信息
BugDTO bugDTO = bugLogService.getOriginalValue(id); BugDTO bugDTO = bugLogService.getOriginalValue(id);
@ -123,17 +120,26 @@ public class BugNoticeService {
// 自定义字段解析{name: value} // 自定义字段解析{name: value}
if (CollectionUtils.isNotEmpty(bugDTO.getCustomFields())) { if (CollectionUtils.isNotEmpty(bugDTO.getCustomFields())) {
List<OptionDTO> fields = new ArrayList<>(); List<OptionDTO> fields = new ArrayList<>();
bugDTO.getCustomFields().forEach(field -> { bugDTO.getCustomFields().forEach(field -> fields.add(buildNoticeOptionDTO(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);
});
notice.setFields(fields); notice.setFields(fields);
} }
return notice; 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); BugMapper batchBugMapper = sqlSession.getMapper(BugMapper.class);
BugContentMapper batchBugContentMapper = sqlSession.getMapper(BugContentMapper.class); BugContentMapper batchBugContentMapper = sqlSession.getMapper(BugContentMapper.class);
List<BugLocalAttachment> picAttachmentsFromPlatform = new ArrayList<>();
// 批量更新缺陷 // 批量更新缺陷
updateBugs.forEach(updateBug -> { updateBugs.forEach(updateBug -> {
// 处理同步的BUG中的富文本图片 // 处理同步的BUG中的富文本图片
syncRichTextToMs(updateBug, platform); picAttachmentsFromPlatform.addAll(syncRichTextPicToMs(updateBug, platform));
updateBug.setCreateUser(null); updateBug.setCreateUser(null);
Bug bug = new Bug(); Bug bug = new Bug();
BeanUtils.copyBean(bug, updateBug); BeanUtils.copyBean(bug, updateBug);
@ -708,6 +709,11 @@ public class BugService {
bugMapper.deleteByPrimaryKey(deleteBugId); bugMapper.deleteByPrimaryKey(deleteBugId);
}); });
// 批量插入同步的三方缺陷富文本附件
if (CollectionUtils.isNotEmpty(picAttachmentsFromPlatform)) {
extBugLocalAttachmentMapper.batchInsert(picAttachmentsFromPlatform);
}
// 同步附件至MS // 同步附件至MS
if (MapUtils.isNotEmpty(syncBugResult.getAttachmentMap())) { if (MapUtils.isNotEmpty(syncBugResult.getAttachmentMap())) {
bugAttachmentService.syncAttachmentToMs(platform, syncBugResult.getAttachmentMap(), project.getId()); bugAttachmentService.syncAttachmentToMs(platform, syncBugResult.getAttachmentMap(), project.getId());
@ -1539,57 +1545,67 @@ public class BugService {
/** /**
* 处理同步缺陷中的富文本图片 * 处理同步缺陷中的富文本图片
* *
* @param updateBug 同步更新的缺陷 * @param syncBug 同步更新的缺陷
* @param platform 平台对象 * @param platform 平台对象
*/ */
private void syncRichTextToMs(PlatformBugDTO updateBug, Platform platform) { public List<BugLocalAttachment> syncRichTextPicToMs(PlatformBugDTO syncBug, Platform platform) {
if (MapUtils.isNotEmpty(updateBug.getRichTextImageMap())) { List<BugLocalAttachment> picsFromPlatform = new ArrayList<>();
Map<String, String> richTextImageMap = updateBug.getRichTextImageMap(); if (MapUtils.isNotEmpty(syncBug.getRichTextImageMap())) {
Map<String, String> richTextImageMap = syncBug.getRichTextImageMap();
try {
// 同步第三方的富文本文件 // 同步第三方的富文本文件
richTextImageMap.keySet().forEach(key -> platform.getAttachmentContent(key, (in) -> { richTextImageMap.keySet().forEach(key -> platform.getAttachmentContent(key, (in) -> {
if (in == null) { if (in == null) {
return; return;
} }
String fileId = IDGenerator.nextStr(); String fileId = IDGenerator.nextStr();
String fileName = updateBug.getPlatform() + "-" + richTextImageMap.get(key); String fileName = syncBug.getPlatform() + "-" + richTextImageMap.get(key);
byte[] bytes; byte[] bytes;
try { try {
// 获取第三方平台附件流 // 获取第三方平台附件流
bytes = in.readAllBytes(); bytes = in.readAllBytes();
// 第三方平台下载的图片默认不压缩 // 第三方平台下载的图片默认不压缩
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(updateBug.getProjectId(), updateBug.getId(), fileId, fileName)); FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(syncBug.getProjectId(), syncBug.getId(), fileId, fileName));
} catch (Exception e) { } catch (Exception e) {
throw new MSException(e.getMessage()); throw new MSException(e.getMessage());
} }
// 保存缺陷附件关系 // 保存缺陷附件关系
BugLocalAttachment localAttachment = new BugLocalAttachment(); BugLocalAttachment localAttachment = new BugLocalAttachment();
localAttachment.setId(IDGenerator.nextStr()); localAttachment.setId(IDGenerator.nextStr());
localAttachment.setBugId(updateBug.getId()); localAttachment.setBugId(syncBug.getId());
localAttachment.setFileId(fileId); localAttachment.setFileId(fileId);
localAttachment.setFileName(fileName); localAttachment.setFileName(fileName);
localAttachment.setSize((long) bytes.length); localAttachment.setSize((long) bytes.length);
localAttachment.setCreateTime(System.currentTimeMillis()); localAttachment.setCreateTime(System.currentTimeMillis());
localAttachment.setCreateUser("admin"); localAttachment.setCreateUser("admin");
localAttachment.setSource(BugAttachmentSourceType.RICH_TEXT.name()); localAttachment.setSource(BugAttachmentSourceType.RICH_TEXT.name());
bugLocalAttachmentMapper.insert(localAttachment); picsFromPlatform.add(localAttachment);
// 替换富文本中的临时URL, 注意: 第三方的图片附件暂未存储在压缩目录, 因此不支持压缩访问 // 替换富文本中的临时URL, 注意: 第三方的图片附件暂未存储在压缩目录, 因此不支持压缩访问
if (StringUtils.contains(updateBug.getDescription(), "alt=\"" + key + "\"")) { String tmpRichUrl = getPlatformTmpRichUrlOfKey(key);
updateBug.setDescription(updateBug.getDescription() if (StringUtils.isBlank(tmpRichUrl)) {
.replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + updateBug.getProjectId() + "/" + fileId + "/false\"")); return;
if (updateBug.getPlatformDefaultTemplate()) { }
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 = updateBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getCustomData(), "description")).toList().getFirst(); PlatformCustomFieldItemDTO descriptionField = syncBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getCustomData(), "description")).toList().getFirst();
descriptionField.setValue(updateBug.getDescription()); descriptionField.setValue(syncBug.getDescription());
} }
} else { } else {
// 来自富文本自定义字段 // 来自富文本自定义字段
PlatformCustomFieldItemDTO richTextField = updateBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getType(), PlatformCustomFieldType.RICH_TEXT.name()) PlatformCustomFieldItemDTO richTextField = syncBug.getCustomFieldList().stream().filter(field -> StringUtils.equals(field.getType(), PlatformCustomFieldType.RICH_TEXT.name())
&& field.getValue() != null && StringUtils.contains(field.getValue().toString(), "alt=\"" + key + "\"")).toList().getFirst(); && field.getValue() != null && StringUtils.contains(field.getValue().toString(), tmpRichUrl)).toList().getFirst();
richTextField.setValue(richTextField.getValue().toString().replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + updateBug.getProjectId() + "/" + fileId + "/false\"")); 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); BeanUtils.copyBean(bugPageRequest, request);
bugPageRequest.setUseTrash(false); bugPageRequest.setUseTrash(false);
if (request.getCondition() != null) { if (request.getCondition() != null) {
bugPageRequest.setCombine(request.getCondition().getCombine()); BeanUtils.copyBean(bugPageRequest, request.getCondition());
bugPageRequest.setFilter(request.getCondition().getFilter());
bugPageRequest.setSearchMode(request.getCondition().getSearchMode());
bugPageRequest.setKeyword(request.getCondition().getKeyword());
} }
List<BugDTO> allBugs = extBugMapper.list(bugPageRequest, request.getSort()); List<BugDTO> allBugs = extBugMapper.list(bugPageRequest, request.getSort());
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
@ -1821,10 +1834,7 @@ public class BugService {
BugPageRequest bugPageRequest = new BugPageRequest(); BugPageRequest bugPageRequest = new BugPageRequest();
BeanUtils.copyBean(bugPageRequest, request); BeanUtils.copyBean(bugPageRequest, request);
if (request.getCondition() != null) { if (request.getCondition() != null) {
bugPageRequest.setCombine(request.getCondition().getCombine()); BeanUtils.copyBean(bugPageRequest, request.getCondition());
bugPageRequest.setFilter(request.getCondition().getFilter());
bugPageRequest.setSearchMode(request.getCondition().getSearchMode());
bugPageRequest.setKeyword(request.getCondition().getKeyword());
} }
List<String> ids = extBugMapper.getIdsByPageRequest(bugPageRequest); List<String> ids = extBugMapper.getIdsByPageRequest(bugPageRequest);
if (CollectionUtils.isNotEmpty(request.getExcludeIds())) { if (CollectionUtils.isNotEmpty(request.getExcludeIds())) {
@ -1996,6 +2006,12 @@ public class BugService {
Map<String, String> needSyncApiFieldMap = new HashMap<>(12); Map<String, String> needSyncApiFieldMap = new HashMap<>(12);
PlatformBugDTO platformBug = saveModel.getPlatformBug(); PlatformBugDTO platformBug = saveModel.getPlatformBug();
Bug originalBug = saveModel.getMsBug(); 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) { if (originalBug == null) {
// 新增 // 新增
@ -2009,12 +2025,6 @@ public class BugService {
platformBug.setDeleteTime(platformBug.getCreateTime()); platformBug.setDeleteTime(platformBug.getCreateTime());
platformBug.setDeleted(false); platformBug.setDeleted(false);
platformBug.setPos(atomicPos.getAndAdd(INTERVAL_POS)); 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 { } else {
// 更新 // 更新
platformBug.setId(originalBug.getId()); platformBug.setId(originalBug.getId());
@ -2029,68 +2039,11 @@ public class BugService {
platformBug.setPlatform(originalBug.getPlatform()); platformBug.setPlatform(originalBug.getPlatform());
platformBug.setCreateUser(null); platformBug.setCreateUser(null);
platformBug.setPlatformDefaultTemplate(isPluginDefaultTemplate(platformBug.getTemplateId(), saveModel.getPluginDefaultTemplate())); 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(); Bug bug = new Bug();
BeanUtils.copyBean(bug, platformBug); BeanUtils.copyBean(bug, platformBug);
// 如果缺陷需要同步第三方的富文本文件 // 如果缺陷需要同步第三方的富文本文件
List<BugLocalAttachment> richTextAttachments = new ArrayList<>(); List<BugLocalAttachment> richTextAttachments = syncRichTextPicToMs(platformBug, saveModel.getPlatform());
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());
}
}
BugContent bugContent = new BugContent(); BugContent bugContent = new BugContent();
bugContent.setBugId(platformBug.getId()); bugContent.setBugId(platformBug.getId());
bugContent.setDescription(platformBug.getDescription()); bugContent.setDescription(platformBug.getDescription());
@ -2143,4 +2096,8 @@ public class BugService {
LogUtils.error(e); LogUtils.error(e);
} }
} }
private String getPlatformTmpRichUrlOfKey(String key) {
return "alt=\"" + key + "\"";
}
} }