refactor(项目报告): 重构报告发送邮件的代码处理逻辑

重构报告发送邮件的代码处理逻辑
This commit is contained in:
song-tianyang 2023-02-15 15:15:36 +08:00 committed by 刘瑞斌
parent 83c938effc
commit 8046e08f34
3 changed files with 145 additions and 112 deletions

View File

@ -12,7 +12,6 @@ import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.*; import io.metersphere.commons.utils.*;
import io.metersphere.dto.UserDTO; import io.metersphere.dto.UserDTO;
import io.metersphere.dto.UserGroupInfoDTO; import io.metersphere.dto.UserGroupInfoDTO;
import io.metersphere.i18n.Translator;
import io.metersphere.log.utils.ReflexObjectUtil; import io.metersphere.log.utils.ReflexObjectUtil;
import io.metersphere.log.vo.DetailColumn; import io.metersphere.log.vo.DetailColumn;
import io.metersphere.log.vo.OperatingLogDetails; import io.metersphere.log.vo.OperatingLogDetails;
@ -25,15 +24,14 @@ import io.metersphere.reportstatistics.dto.request.EnterpriseTestReportRequest;
import io.metersphere.reportstatistics.dto.request.emun.EnterpriseReportStatus; import io.metersphere.reportstatistics.dto.request.emun.EnterpriseReportStatus;
import io.metersphere.reportstatistics.dto.response.EnterpriseTestReportDTO; import io.metersphere.reportstatistics.dto.response.EnterpriseTestReportDTO;
import io.metersphere.reportstatistics.dto.response.UserGroupResponse; import io.metersphere.reportstatistics.dto.response.UserGroupResponse;
import io.metersphere.reportstatistics.dto.table.TestCaseCountTableDataDTO;
import io.metersphere.reportstatistics.dto.table.TestCaseCountTableItemDataDTO;
import io.metersphere.reportstatistics.dto.table.TestCaseCountTableRowDTO;
import io.metersphere.reportstatistics.job.SendReportJob; import io.metersphere.reportstatistics.job.SendReportJob;
import io.metersphere.reportstatistics.utils.EmailPageInfoUtil;
import io.metersphere.reportstatistics.utils.JSONUtil; import io.metersphere.reportstatistics.utils.JSONUtil;
import io.metersphere.reportstatistics.utils.ScheduleUtil; import io.metersphere.reportstatistics.utils.ScheduleUtil;
import io.metersphere.request.ScheduleRequest; import io.metersphere.request.ScheduleRequest;
import io.metersphere.service.BaseScheduleService; import io.metersphere.service.BaseScheduleService;
import io.metersphere.service.BaseUserService; import io.metersphere.service.BaseUserService;
import jakarta.annotation.Resource;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils; import org.apache.commons.collections.MapUtils;
@ -43,7 +41,6 @@ import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL; import java.net.URL;
@ -345,44 +342,76 @@ public class EnterpriseTestReportService {
mailNoticeSender.sendExternalMail(context, noticeModel); mailNoticeSender.sendExternalMail(context, noticeModel);
} }
private String genReportContent(EnterpriseTestReportWithBLOBs report, boolean isSchedule) throws Exception { private String formatPreviewContent(String previewContent) {
StringBuffer returnReportContentBuffer = new StringBuffer(); previewContent = StringUtils.replace(previewContent, "class=\"hljs-center\"", "style=\"text-align: center\"");
List<EnterpriseReportContentStep> stepList = JSONUtil.parseArray(report.getReportContent(), EnterpriseReportContentStep.class); previewContent = StringUtils.replace(previewContent, "class=\"hljs-right\"", "style=\"text-align: right\"");
previewContent = StringUtils.replace(previewContent, "class=\"hljs-left\"", "style=\"text-align: left\"");
return previewContent;
}
private boolean isReportStep(String stepType) {
return StringUtils.equalsIgnoreCase(stepType, EmailPageInfoUtil.STEP_TYPE_REPORT);
}
private boolean isRichTextStep(String stepType) {
return StringUtils.equalsIgnoreCase(stepType, EmailPageInfoUtil.STEP_TYPE_TXT);
}
private String genReportContent(EnterpriseTestReportWithBLOBs report, boolean isSchedule) {
StringBuilder reportContent = new StringBuilder();
UserDTO user = baseUserService.getUserDTO(report.getCreateUser()); UserDTO user = baseUserService.getUserDTO(report.getCreateUser());
List<EnterpriseReportContentStep> stepList = JSONUtil.parseArray(report.getReportContent(), EnterpriseReportContentStep.class);
Map<String, String> syncReportMap = this.getSyncReportMap(stepList, user, isSchedule); Map<String, String> syncReportMap = this.getSyncReportMap(stepList, user, isSchedule);
for (EnterpriseReportContentStep step : stepList) { for (EnterpriseReportContentStep step : stepList) {
String title = "<div style=\"background-color: #783887;font-size: 16px;color: white;margin: 5px;width: 100%; line-height:30px\">\n" + String title = EmailPageInfoUtil.generateEmailStepTitle(step.getName());
"<span style=\"margin-left: 5px\">" + step.getName() + StringUtils.LF + reportContent.append(title);
"</span>\n" + if (isRichTextStep(step.getType())) {
"</div>"; String previweContent = this.formatPreviewContent(step.getPreviewContext());
returnReportContentBuffer.append(title); //判断富文本内容中是否含有图片
if (StringUtils.equalsIgnoreCase(step.getType(), "txt")) { if (StringUtils.contains(previweContent, EmailPageInfoUtil.IMG_DATA_PREFIX)
String previweContent = step.getPreviewContext(); && StringUtils.contains(previweContent, EmailPageInfoUtil.IMG_DATA_CONTAINS)) {
previweContent = StringUtils.replace(previweContent, "class=\"hljs-center\"", "style=\"text-align: center\""); previweContent = this.formatStepImageInfo(previweContent);
previweContent = StringUtils.replace(previweContent, "class=\"hljs-right\"", "style=\"text-align: right\""); }
previweContent = StringUtils.replace(previweContent, "class=\"hljs-left\"", "style=\"text-align: left\""); reportContent.append(previweContent);
if (StringUtils.contains(previweContent, "<img src=\"/resource/md/get") && StringUtils.contains(previweContent, "\" alt=\"")) { } else if (isReportStep(step.getType())) {
String[] previewContentArr = StringUtils.splitByWholeSeparator(StringUtils.SPACE + previweContent, "<img src=\"/resource/md/get"); if (isSchedule) {
//定时任务触发的数据需要检查图片是否需要重新生成如果生成不成功就不贴图
String imageFile = syncReportMap.get(step.getReportRecordId());
if (StringUtils.isNotEmpty(imageFile)) {
step.setRecordImageContent(imageFile);
} else {
step.setRecordImageContent(null);
}
}
if (StringUtils.isNotEmpty(step.getRecordImageContent())) {
reportContent.append(EmailPageInfoUtil.generatePicInfo(step.getReportRecordId(), step.getRecordImageContent()));
}
if (step.getReportRecordData() != null && step.getReportRecordData().containsKey("showTable")) {
reportContent.append(EmailPageInfoUtil.generateTableInfo(step.getReportRecordData()));
}
}
}
return reportContent.toString();
}
private String formatStepImageInfo(String previewContent) {
String[] previewContentArr = StringUtils.splitByWholeSeparator(StringUtils.SPACE + previewContent, EmailPageInfoUtil.IMG_DATA_PREFIX);
if (previewContentArr.length > 1) { if (previewContentArr.length > 1) {
for (int i = 1; i < previewContentArr.length; i++) { for (int i = 1; i < previewContentArr.length; i++) {
String itemStr = previewContentArr[i]; String itemStr = previewContentArr[i];
int containsIndex = StringUtils.indexOf(itemStr, "\" alt=\""); int containsIndex = StringUtils.indexOf(itemStr, EmailPageInfoUtil.IMG_DATA_CONTAINS);
if (containsIndex > 0) { if (containsIndex > 0) {
String fileNameStr = StringUtils.substring(itemStr, 0, containsIndex); String fileNameStr = StringUtils.substring(itemStr, 0, containsIndex);
String fileName = fileNameStr; String decodeFileName = StringUtils.startsWith(fileNameStr, "?fileName=") ? fileNameStr.substring(10) : fileNameStr;
if (StringUtils.startsWith(fileName, "?fileName=")) { String encodedFileName = URLDecoder.decode(decodeFileName, StandardCharsets.UTF_8);
fileName = fileName.substring(10, fileName.length()); String dataType = StringUtils.endsWithIgnoreCase(encodedFileName, ".png") ?
} EmailPageInfoUtil.IMG_DATA_TYPE_PNG : EmailPageInfoUtil.IMG_DATA_TYPE_JPG;
String encodedFileName = URLDecoder.decode(fileName, "UTF-8");
String dataType = "data:image/jpeg;";
if (StringUtils.endsWithIgnoreCase(encodedFileName, ".png")) {
dataType = "data:image/png;";
}
try { try {
String fileContent = "<img src=\"" + dataType + "base64," + this.getImageContext(encodedFileName) + "\""; String fileContent = "<img src=\"" + dataType + "base64," + this.getImageContext(encodedFileName) + "\"";
previweContent = StringUtils.replace(previweContent, "<img src=\"/resource/md/get" + fileNameStr + "\"", fileContent); previewContent = StringUtils.replace(previewContent, EmailPageInfoUtil.IMG_DATA_PREFIX + fileNameStr + "\"", fileContent);
} catch (Exception exception) { } catch (Exception exception) {
LogUtil.error(exception); LogUtil.error(exception);
} }
@ -390,95 +419,22 @@ public class EnterpriseTestReportService {
} }
} }
} }
} return previewContent;
returnReportContentBuffer.append(previweContent);
} else if (StringUtils.equalsIgnoreCase(step.getType(), "report")) {
if (isSchedule) {
//定时任务触发的数据需要检查图片是否需要重新生成
String imageFile = syncReportMap.get(step.getReportRecordId());
if (StringUtils.isNotEmpty(imageFile)) {
step.setRecordImageContent(imageFile);
}
}
String reportPic = "<img style=\"width: 100%;\" src=\"" + step.getRecordImageContent() + "\" alt=\"" + step.getReportRecordId() + ".jpg\" rel=\"1\" />";
returnReportContentBuffer.append(reportPic);
if (step.getReportRecordData() != null && step.getReportRecordData().containsKey("showTable")) {
StringBuffer tableBuffer = new StringBuffer();
tableBuffer.append("<table cellspacing=\"0\" cellpadding=\"0\" style=\"width: 100%;border: 1px\">");
try {
String showTableJsonStr = JSON.toJSONString(step.getReportRecordData().get("showTable"));
TestCaseCountTableDataDTO showTable = JSON.parseObject(showTableJsonStr, TestCaseCountTableDataDTO.class);
tableBuffer.append("<tr style=\"font-size: 14px;font-weight: 700;color: #909399;text-align: left;\">");
for (TestCaseCountTableItemDataDTO itemData : showTable.getHeads()) {
String tableHeadValue = itemData.getValue();
switch (tableHeadValue) {
case "testCase":
tableHeadValue = Translator.get("test_case");
break;
case "apiCase":
tableHeadValue = Translator.get("api_case");
break;
case "scenarioCase":
tableHeadValue = Translator.get("scenario_case");
break;
case "performanceCase":
tableHeadValue = Translator.get("performance_case");
break;
case "creator":
tableHeadValue = Translator.get("create_user");
break;
case "casetype":
tableHeadValue = Translator.get("test_case_type");
break;
case "casestatus":
tableHeadValue = Translator.get("test_case_status");
break;
case "caselevel":
tableHeadValue = Translator.get("test_case_priority");
break;
case "Count":
tableHeadValue = Translator.get("count");
break;
}
tableBuffer.append("<th style=\"border: 1px solid #E8EBF3; padding: 6px 10px\">" + tableHeadValue + "</th>");
}
tableBuffer.append("</tr>");
for (TestCaseCountTableRowDTO row : showTable.getData()) {
tableBuffer.append("<tr style=\"font-size: 14px;font-weight: 700;color: #909399;text-align: left;\">");
for (TestCaseCountTableItemDataDTO itemData : row.getTableDatas()) {
tableBuffer.append("<td style=\"border: 1px solid #E8EBF3; padding: 6px 10px\">" + itemData.getValue() + "</td>");
}
tableBuffer.append("</tr>");
}
} catch (Exception e) {
LogUtil.error("解析表格数据出错!", e);
}
tableBuffer.append("</table>");
returnReportContentBuffer.append(tableBuffer);
}
}
}
return returnReportContentBuffer.toString();
} }
private Map<String, String> getSyncReportMap(List<EnterpriseReportContentStep> stepList, User user, boolean isSchedule) { private Map<String, String> getSyncReportMap(List<EnterpriseReportContentStep> stepList, User user, boolean isSchedule) {
Map<String, String> returnMap = new HashMap<>(); Map<String, String> returnMap = new HashMap<>();
if (isSchedule) { if (isSchedule) {
//定时任务触发的数据需要检查图片是否需要重新生成
String language = null; String language = null;
if (user != null) { if (user != null) {
language = user.getLanguage(); language = user.getLanguage();
} }
List<ReportStatisticsWithBLOBs> bloBsList = new ArrayList<>(); List<ReportStatisticsWithBLOBs> bloBsList = new ArrayList<>();
for (EnterpriseReportContentStep step : stepList) { for (EnterpriseReportContentStep step : stepList) {
//定时任务触发的数据需要检查图片是否需要重新生成
ReportStatisticsWithBLOBs reportStatisticsWithBLOBs = reportStatisticsService.selectById(step.getReportRecordId(), false); ReportStatisticsWithBLOBs reportStatisticsWithBLOBs = reportStatisticsService.selectById(step.getReportRecordId(), false);
if (reportStatisticsWithBLOBs != null) { if (reportStatisticsWithBLOBs != null) {
boolean needSyncImage = reportStatisticsService.isReportNeedUpdate(reportStatisticsWithBLOBs); boolean needSyncImage = reportStatisticsService.reportHasUpdated(reportStatisticsWithBLOBs);
if (needSyncImage) { if (needSyncImage) {
bloBsList.add(reportStatisticsWithBLOBs); bloBsList.add(reportStatisticsWithBLOBs);
} }

View File

@ -13,12 +13,12 @@ import io.metersphere.reportstatistics.dto.table.TestCaseCountTableItemDataDTO;
import io.metersphere.reportstatistics.dto.table.TestCaseCountTableRowDTO; import io.metersphere.reportstatistics.dto.table.TestCaseCountTableRowDTO;
import io.metersphere.reportstatistics.utils.ChromeUtil; import io.metersphere.reportstatistics.utils.ChromeUtil;
import io.metersphere.service.SystemParameterService; import io.metersphere.service.SystemParameterService;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import jakarta.annotation.Resource;
import java.util.*; import java.util.*;
/** /**
@ -83,7 +83,7 @@ public class ReportStatisticsService {
Map<String, Object> selectOption = JSON.parseObject(blob.getSelectOption(), Map.class); Map<String, Object> selectOption = JSON.parseObject(blob.getSelectOption(), Map.class);
Map<String, Object> dataOption = JSON.parseObject(blob.getDataOption(), Map.class); Map<String, Object> dataOption = JSON.parseObject(blob.getDataOption(), Map.class);
boolean isReportNeedUpdate = this.isReportNeedUpdate(blob); boolean isReportNeedUpdate = this.reportHasUpdated(blob);
if (isReportNeedUpdate) { if (isReportNeedUpdate) {
TestCaseCountRequest countRequest = JSON.parseObject(blob.getSelectOption(), TestCaseCountRequest.class); TestCaseCountRequest countRequest = JSON.parseObject(blob.getSelectOption(), TestCaseCountRequest.class);
Map<String, Object> returnDataOption = this.reloadData(countRequest, dataOption.get("chartType").toString()); Map<String, Object> returnDataOption = this.reloadData(countRequest, dataOption.get("chartType").toString());
@ -298,7 +298,7 @@ public class ReportStatisticsService {
return returnMap; return returnMap;
} }
public boolean isReportNeedUpdate(ReportStatisticsWithBLOBs model) { public boolean reportHasUpdated(ReportStatisticsWithBLOBs model) {
Map<String, Object> selectOption = JSON.parseObject(model.getSelectOption(), Map.class); Map<String, Object> selectOption = JSON.parseObject(model.getSelectOption(), Map.class);
return selectOption.containsKey("timeType") && StringUtils.equalsIgnoreCase("dynamicTime", String.valueOf(selectOption.get("timeType"))); return selectOption.containsKey("timeType") && StringUtils.equalsIgnoreCase("dynamicTime", String.valueOf(selectOption.get("timeType")));
} }

View File

@ -0,0 +1,77 @@
package io.metersphere.reportstatistics.utils;
import io.metersphere.commons.utils.JSON;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.i18n.Translator;
import io.metersphere.reportstatistics.dto.table.TestCaseCountTableDataDTO;
import io.metersphere.reportstatistics.dto.table.TestCaseCountTableItemDataDTO;
import io.metersphere.reportstatistics.dto.table.TestCaseCountTableRowDTO;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
public class EmailPageInfoUtil {
public static final String STEP_TYPE_TXT = "txt";
public static final String STEP_TYPE_REPORT = "report";
//数据前缀--图片
public static final String IMG_DATA_PREFIX = "<img src=\"/resource/md/get";
public static final String IMG_DATA_CONTAINS = "\" alt=\"";
public static final String IMG_DATA_TYPE_JPG = "data:image/jpeg;";
public static final String IMG_DATA_TYPE_PNG = "data:image/png;";
public static String generateEmailStepTitle(String stepName) {
return StringUtils.join(
"<div style=\"background-color: #783887;font-size: 16px;color: white;margin: 5px;width: 100%; line-height:30px\">", StringUtils.LF,
"<span style=\"margin-left: 5px\">",
stepName, StringUtils.LF,
"</span>", StringUtils.LF,
"</div>"
);
}
public static String generateTableInfo(Map<String, Object> reportRecordData) {
StringBuilder tableBuffer = new StringBuilder();
tableBuffer.append("<table cellspacing=\"0\" cellpadding=\"0\" style=\"width: 100%;border: 1px\">");
try {
String showTableJsonStr = JSON.toJSONString(reportRecordData.get("showTable"));
TestCaseCountTableDataDTO showTable = JSON.parseObject(showTableJsonStr, TestCaseCountTableDataDTO.class);
tableBuffer.append("<tr style=\"font-size: 14px;font-weight: 700;color: #909399;text-align: left;\">");
for (TestCaseCountTableItemDataDTO itemData : showTable.getHeads()) {
String tableHeadValue = switch (itemData.getValue()) {
case "testCase" -> Translator.get("test_case");
case "apiCase" -> Translator.get("api_case");
case "scenarioCase" -> Translator.get("scenario_case");
case "performanceCase" -> Translator.get("performance_case");
case "creator" -> Translator.get("create_user");
case "casetype" -> Translator.get("test_case_type");
case "casestatus" -> Translator.get("test_case_status");
case "caselevel" -> Translator.get("test_case_priority");
case "Count" -> Translator.get("count");
default -> itemData.getValue();
};
tableBuffer.append("<th style=\"border: 1px solid #E8EBF3; padding: 6px 10px\">").append(tableHeadValue).append("</th>");
}
tableBuffer.append("</tr>");
for (TestCaseCountTableRowDTO row : showTable.getData()) {
tableBuffer.append("<tr style=\"font-size: 14px;font-weight: 700;color: #909399;text-align: left;\">");
for (TestCaseCountTableItemDataDTO itemData : row.getTableDatas()) {
tableBuffer.append("<td style=\"border: 1px solid #E8EBF3; padding: 6px 10px\">").append(itemData.getValue()).append("</td>");
}
tableBuffer.append("</tr>");
}
} catch (Exception e) {
LogUtil.error("解析表格数据出错!", e);
}
tableBuffer.append("</table>");
return tableBuffer.toString();
}
public static String generatePicInfo(String reportRecordId, String imageContent) {
return "<img style=\"width: 100%;\" src=\"" + imageContent + EmailPageInfoUtil.IMG_DATA_CONTAINS + reportRecordId + ".jpg\" rel=\"1\" />";
}
}