fix(缺陷管理): 富文本图片同步问题

This commit is contained in:
song-cc-rock 2024-03-22 12:33:28 +08:00 committed by 刘瑞斌
parent 1c6d4a64aa
commit 364d8c9a18
7 changed files with 80 additions and 25 deletions

View File

@ -2,6 +2,8 @@ package io.metersphere.plugin.platform.dto.reponse;
import lombok.Data;
import java.util.Map;
@Data
public class PlatformBugUpdateDTO {
@ -25,4 +27,8 @@ public class PlatformBugUpdateDTO {
* 平台描述
*/
private String platformDescription;
/**
* 平台自定义字段值
*/
private Map<String, String> platformCustomFieldMap;
}

View File

@ -327,7 +327,7 @@ public class BugAttachmentService {
try {
// upload platform attachment to minio
bytes = in.readAllBytes();
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(projectId, bugId, fileId, fileName));
FileCenter.getDefaultRepository().saveFile(bytes, buildBugFileRequest(projectId, bugId, fileId, fileName, false));
} catch (Exception e) {
throw new MSException(e.getMessage());
}
@ -382,7 +382,7 @@ public class BugAttachmentService {
deleteLocalIds.forEach(deleteLocalId -> {
try {
BugFileDTO bugFileDTO = localFileMap.get(deleteLocalId);
FileCenter.getDefaultRepository().delete(buildBugFileRequest(projectId, bugId, bugFileDTO.getFileId(), bugFileDTO.getFileName()));
FileCenter.getDefaultRepository().delete(buildBugFileRequest(projectId, bugId, bugFileDTO.getFileId(), bugFileDTO.getFileName(), false));
} catch (Exception e) {
throw new MSException(e.getMessage());
}
@ -406,7 +406,7 @@ public class BugAttachmentService {
* @return 文件字节流
*/
public byte[] getLocalFileBytes(BugLocalAttachment attachment, String projectId, String bugId) {
FileRequest fileRequest = buildBugFileRequest(projectId, bugId, attachment.getFileId(), attachment.getFileName());
FileRequest fileRequest = buildBugFileRequest(projectId, bugId, attachment.getFileId(), attachment.getFileName(), false);
byte[] bytes;
try {
bytes = fileService.download(fileRequest);
@ -477,7 +477,7 @@ public class BugAttachmentService {
record.setCreateUser(currentUser);
bugLocalAttachmentMapper.insert(record);
List<SyncAttachmentToPlatformRequest> localSyncFiles = new ArrayList<>();
FileRequest fileRequest = buildBugFileRequest(projectId, bugId, record.getFileId(), file.getOriginalFilename());
FileRequest fileRequest = buildBugFileRequest(projectId, bugId, record.getFileId(), file.getOriginalFilename(), false);
try {
fileService.upload(file, fileRequest);
if (!StringUtils.equals(platformName, BugPlatform.LOCAL.getName())) {
@ -534,7 +534,7 @@ public class BugAttachmentService {
List<SyncAttachmentToPlatformRequest> syncLocalFiles = new ArrayList<>();
BugLocalAttachment localAttachment = bugLocalAttachmentMapper.selectByPrimaryKey(refId);
// 删除本地上传的附件, BUG_LOCAL_ATTACHMENT表
FileRequest fileRequest = buildBugFileRequest(projectId, bugId, localAttachment.getFileId(), localAttachment.getFileName());
FileRequest fileRequest = buildBugFileRequest(projectId, bugId, localAttachment.getFileId(), localAttachment.getFileName(), false);
try {
// 删除MINIO附件
fileService.deleteFile(fileRequest);
@ -586,11 +586,16 @@ public class BugAttachmentService {
* @param resourceId 资源ID
* @param fileId 文件ID
* @param fileName 文件名称
* @param compress 是否压缩预览目录
* @return 文件请求对象
*/
private FileRequest buildBugFileRequest(String projectId, String resourceId, String fileId, String fileName) {
private FileRequest buildBugFileRequest(String projectId, String resourceId, String fileId, String fileName, boolean compress) {
FileRequest fileRequest = new FileRequest();
fileRequest.setFolder(DefaultRepositoryDir.getBugDir(projectId, resourceId) + "/" + fileId);
if (compress) {
fileRequest.setFolder(DefaultRepositoryDir.getBugPreviewDir(projectId, resourceId) + "/" + fileId);
} else {
fileRequest.setFolder(DefaultRepositoryDir.getBugDir(projectId, resourceId) + "/" + fileId);
}
fileRequest.setFileName(StringUtils.isEmpty(fileName) ? null : fileName);
fileRequest.setStorage(StorageType.MINIO.name());
return fileRequest;
@ -763,14 +768,7 @@ public class BugAttachmentService {
//在正式目录获取
BugLocalAttachment attachment = bugAttachments.get(0);
fileName = attachment.getFileName();
FileRequest fileRequest = new FileRequest();
fileRequest.setFileName(attachment.getFileName());
if (compressed) {
fileRequest.setFolder(DefaultRepositoryDir.getBugPreviewDir(projectId, attachment.getBugId()) + "/" + attachment.getFileId());
} else {
fileRequest.setFolder(DefaultRepositoryDir.getBugDir(projectId, attachment.getBugId()) + "/" + attachment.getFileId());
}
fileRequest.setStorage(StorageType.MINIO.name());
FileRequest fileRequest = buildBugFileRequest(projectId, attachment.getBugId(), attachment.getFileId(), attachment.getFileName(), compressed);
try {
bytes = fileService.download(fileRequest);
} catch (Exception e) {

View File

@ -27,6 +27,9 @@ public class BugPlatformService {
public void syncAttachmentToPlatform(List<SyncAttachmentToPlatformRequest> platformAttachments, String projectId) {
// 平台缺陷需同步附件
Platform platform = projectApplicationService.getPlatform(projectId, true);
if (!platform.isSupportAttachment()) {
return;
}
platformAttachments.forEach(attachment -> {
platform.syncAttachmentToPlatform(attachment);
try {

View File

@ -17,6 +17,7 @@ import io.metersphere.plugin.platform.dto.reponse.PlatformBugDTO;
import io.metersphere.plugin.platform.dto.reponse.PlatformBugUpdateDTO;
import io.metersphere.plugin.platform.dto.reponse.PlatformCustomFieldItemDTO;
import io.metersphere.plugin.platform.dto.request.*;
import io.metersphere.plugin.platform.enums.PlatformCustomFieldType;
import io.metersphere.plugin.platform.enums.SyncAttachmentType;
import io.metersphere.plugin.platform.spi.Platform;
import io.metersphere.project.domain.*;
@ -227,7 +228,7 @@ public class BugService {
// 处理基础字段
Bug bug = handleAndSaveBug(request, currentUser, platformName, platformBug);
// 处理自定义字段
handleAndSaveCustomFields(request, isUpdate);
handleAndSaveCustomFields(request, isUpdate, platformBug);
// 处理附件
handleAndSaveAttachments(request, files, currentUser, platformName, platformBug);
// 处理富文本临时文件
@ -639,7 +640,7 @@ public class BugService {
return bugCustomFieldDTO;
}).collect(Collectors.toList());
customEditRequest.setCustomFields(bugCustomFieldDTOList);
handleAndSaveCustomFields(customEditRequest, true);
handleAndSaveCustomFields(customEditRequest, true, null);
});
// 批量删除缺陷
@ -879,7 +880,7 @@ public class BugService {
*
* @param request 请求参数
*/
public void handleAndSaveCustomFields(BugEditRequest request, boolean merge) {
public void handleAndSaveCustomFields(BugEditRequest request, boolean merge, PlatformBugUpdateDTO platformBug) {
// 处理ID, 值的映射关系
Map<String, String> customFieldMap = request.getCustomFields().stream()
.filter(f -> StringUtils.isNotBlank(f.getId()))
@ -887,6 +888,11 @@ public class BugService {
if (MapUtils.isEmpty(customFieldMap)) {
return;
}
// 拦截, 如果平台返回结果存在自定义字段值, 替换
if (platformBug != null && MapUtils.isNotEmpty(platformBug.getPlatformCustomFieldMap())) {
Map<String, String> platformCustomFieldMap = platformBug.getPlatformCustomFieldMap();
platformCustomFieldMap.keySet().forEach(key -> customFieldMap.put(key, platformCustomFieldMap.get(key)));
}
List<BugCustomField> addFields = new ArrayList<>();
List<BugCustomField> updateFields = new ArrayList<>();
if (merge) {
@ -1285,7 +1291,20 @@ public class BugService {
localAttachment.setSource(BugAttachmentSourceType.RICH_TEXT.name());
bugLocalAttachmentMapper.insert(localAttachment);
// 替换富文本中的临时URL, 注意: 第三方的图片附件暂未存储在压缩目录, 因此不支持压缩访问
updateBug.setDescription(updateBug.getDescription().replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + updateBug.getProjectId() + "/" + fileId + "/false\""));
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().get(0);
descriptionField.setValue(updateBug.getDescription());
}
} 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().get(0);
richTextField.setValue(richTextField.getValue().toString().replace("alt=\"" + key + "\"", "src=\"/bug/attachment/preview/md/" + updateBug.getProjectId() + "/" + fileId + "/false\""));
}
}));
}
}

View File

@ -605,6 +605,7 @@ public class BugControllerTests extends BaseTest {
summary.setType("INPUT");
summary.setValue("这是一个系统Jira模板创建的缺陷");
addRequest.getCustomFields().add(summary);
addRequest.setRichTextTmpFileIds(List.of("rich-text-file-id"));
MultiValueMap<String, Object> addParam3 = getMultiPartParam(addRequest, null);
this.requestMultipart(BUG_ADD, addParam3).andExpect(status().is5xxServerError());
@ -612,6 +613,7 @@ public class BugControllerTests extends BaseTest {
this.requestGetWithOk(BUG_SYNC + "/default-project-for-bug");
// 添加没有附件的Jira缺陷
addRequest.setRichTextTmpFileIds(null);
addRequest.setLinkFileIds(null);
addRequest.setTemplateId("default-bug-template-id");
MultiValueMap<String, Object> addParam2 = getMultiPartParam(addRequest, null);

View File

@ -47,8 +47,10 @@
<MsRichText
v-if="contentEditAble"
v-model:raw="item.defaultValue"
v-model:filed-ids="descriptionFileIdMap[item.fieldId]"
:disabled="!contentEditAble"
:placeholder="t('editor.placeholder')"
:upload-image="handleUploadImage"
:preview-url="EditorPreviewFileUrl"
/>
<div v-else v-dompurify-html="item?.defaultValue || '-'" class="markdown-body"></div>
@ -257,6 +259,7 @@
const acceptType = ref('none'); // -
// -ID
const descriptionFileIds = ref<string[]>([]);
const descriptionFileIdMap = ref<Record<string, string[]>>({});
const imageUrl = ref<string>('');
const associatedDrawer = ref(false);
const fileListRef = ref<InstanceType<typeof MsFileList>>();
@ -442,6 +445,16 @@
return data;
}
function getDescriptionFileId() {
const fileIds = [] as string[];
Object.keys(descriptionFileIdMap.value).forEach((key) => {
if (descriptionFileIdMap.value[key].length > 0) {
fileIds.push(...descriptionFileIdMap.value[key]);
}
});
return fileIds;
}
//
async function handleSave() {
try {
@ -481,7 +494,7 @@
unLinkRefIds: form.value.unLinkRefIds,
linkFileIds: form.value.linkFileIds,
customFields,
richTextTmpFileIds: descriptionFileIds.value,
richTextTmpFileIds: props.isPlatformDefaultTemplate ? getDescriptionFileId() : descriptionFileIds.value,
};
if (!props.isPlatformDefaultTemplate) {
tmpObj.description = form.value.description;
@ -521,8 +534,6 @@
}
watchEffect(() => {
console.log(props.currentPlatform);
console.log(props.detailInfo.platform);
initCurrentDetail(props.detailInfo);
});
defineExpose({
@ -552,4 +563,4 @@
:deep(.arco-form-item-label) {
font-weight: bold !important;
}
</style>
</style>

View File

@ -63,6 +63,9 @@
<MsRichText
v-if="platformSystemFieldMap[key].type === 'RICH_TEXT'"
v-model:raw="form.platformSystemFields[key]"
v-model:filed-ids="descriptionFileIdMap[key]"
:upload-image="handleUploadImage"
:preview-url="EditorPreviewFileUrl"
/>
</a-form-item>
</div>
@ -316,8 +319,10 @@
const isPlatformDefaultTemplate = ref(false);
const imageUrl = ref('');
const previewVisible = ref<boolean>(false);
// -ID
// /ID
const descriptionFileIds = ref<string[]>([]);
// -/ID
const descriptionFileIdMap = ref<Record<string, string[]>>({});
const visitedKey = 'doNotNextTipCreateBug';
const { getIsVisited } = useVisit(visitedKey);
@ -532,6 +537,16 @@
fileList.value.push(...fileResultList);
}
function getDescriptionFileId() {
const fileIds = [] as string[];
Object.keys(descriptionFileIdMap.value).forEach((key) => {
if (descriptionFileIdMap.value[key].length > 0) {
fileIds.push(...descriptionFileIdMap.value[key]);
}
});
return fileIds;
}
//
const saveHandler = async (isContinue = false) => {
formRef.value.validate((error: any) => {
@ -583,11 +598,12 @@
};
});
}
const tmpObj: BugEditFormObject = {
...form.value,
customFields,
copyFiles,
richTextTmpFileIds: descriptionFileIds.value,
richTextTmpFileIds: isPlatformDefaultTemplate.value ? getDescriptionFileId() : descriptionFileIds.value,
};
if (isCopy.value) {
delete tmpObj.id;