[improve] email notice template use the common render (#2775)

Signed-off-by: tomsun28 <tomsun28@outlook.com>
This commit is contained in:
tomsun28 2024-10-15 23:48:39 +08:00 committed by GitHub
parent a0995d26ec
commit efa2dc3969
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 43 additions and 274 deletions

View File

@ -106,7 +106,11 @@ abstract class AbstractAlertNotifyHandlerImpl implements AlertNotifyHandler {
model.put("content", alert.getContent());
model.put("tagsLabel", bundle.getString("alerter.notify.tags"));
model.put("tags", alert.getTags());
// Single instance reuse cache considers mulitple-threading issues
if (alerterProperties != null) {
model.put("consoleUrl", alerterProperties.getConsoleUrl());
}
model.put("consoleLabel", bundle.getString("alerter.notify.console"));
// TODO Single instance reuse cache considers multiple-threading issues
String templateName = "freeMakerTemplate";
stringLoader.putTemplate(templateName, noticeTemplate.getContent());
cfg.setTemplateLoader(stringLoader);

View File

@ -30,10 +30,8 @@ import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
import org.apache.hertzbeat.common.util.ResourceBundleUtil;
import org.apache.hertzbeat.manager.component.alerter.AlertNotifyHandler;
import org.apache.hertzbeat.manager.dao.GeneralConfigDao;
import org.apache.hertzbeat.manager.pojo.dto.EmailNoticeSender;
import org.apache.hertzbeat.manager.service.MailService;
import org.apache.hertzbeat.manager.support.exception.AlertNoticeException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
@ -48,12 +46,10 @@ import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
@Slf4j
public class EmailAlertNotifyHandlerImpl implements AlertNotifyHandler {
public class EmailAlertNotifyHandlerImpl extends AbstractAlertNotifyHandlerImpl {
private final JavaMailSender javaMailSender;
private final MailService mailService;
@Value("${spring.mail.host:smtp.demo.com}")
private String host;
@ -127,7 +123,7 @@ public class EmailAlertNotifyHandlerImpl implements AlertNotifyHandler {
messageHelper.setTo(receiver.getEmail());
messageHelper.setSentDate(new Date());
// Build email templates
String process = mailService.buildAlertHtmlTemplate(alert, noticeTemplate);
String process = renderContent(noticeTemplate, alert);
// Set Email Content Template
messageHelper.setText(process, true);
javaMailSender.send(mimeMessage);

View File

@ -1,40 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hertzbeat.manager.service;
import freemarker.template.TemplateException;
import java.io.IOException;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
/**
* Email delivery service
* @version 1.0
*/
public interface MailService {
/**
* Build an alert email template
* @param alert Alarm data element information
* @param noticeTemplate NoticeTemplate information
* @return content of email
* @throws IOException IOException information
* @throws TemplateException Freemarker TemplateException information
*/
String buildAlertHtmlTemplate(Alert alert, NoticeTemplate noticeTemplate) throws IOException, TemplateException;
}

View File

@ -1,113 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hertzbeat.manager.service.impl;
import freemarker.cache.StringTemplateLoader;
import freemarker.core.TemplateClassResolver;
import freemarker.template.Configuration;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.hertzbeat.alert.AlerterProperties;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.common.support.event.SystemConfigChangeEvent;
import org.apache.hertzbeat.common.util.ResourceBundleUtil;
import org.apache.hertzbeat.manager.service.MailService;
import org.apache.hertzbeat.manager.service.NoticeConfigService;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
/**
* Mailbox sending service interface implementation class
*/
@Slf4j
@Service
public class MailServiceImpl implements MailService {
@Resource
private AlerterProperties alerterProperties;
@Resource
protected NoticeConfigService noticeConfigService;
private ResourceBundle bundle = ResourceBundleUtil.getBundle("alerter");
private final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public String buildAlertHtmlTemplate(final Alert alert, NoticeTemplate noticeTemplate) throws IOException, TemplateException {
freemarker.template.Template templateMail = null;
Configuration cfg = new Configuration(Configuration.VERSION_2_3_0);
String monitorId = null;
String monitorName = null;
String monitorHost = null;
if (alert.getTags() != null) {
monitorId = alert.getTags().get(CommonConstants.TAG_MONITOR_ID);
monitorName = alert.getTags().get(CommonConstants.TAG_MONITOR_NAME);
monitorHost = alert.getTags().get(CommonConstants.TAG_MONITOR_HOST);
}
monitorId = monitorId == null ? "External Alarm, No ID" : monitorId;
monitorName = monitorName == null ? "External Alarm, No Name" : monitorName;
monitorHost = monitorHost == null ? "External Alarm, No Host" : monitorHost;
// Introduce context parameters to render pages
Map<String, String> model = new HashMap<>(16);
model.put("nameTitle", bundle.getString("alerter.notify.title"));
model.put("nameMonitorId", bundle.getString("alerter.notify.monitorId"));
model.put("nameMonitorName", bundle.getString("alerter.notify.monitorName"));
model.put("nameMonitorHost", bundle.getString("alerter.notify.monitorHost"));
model.put("target", alert.getTarget());
model.put("monitorId", monitorId);
model.put("monitorName", monitorName);
model.put("monitorHost", monitorHost);
model.put("nameTarget", bundle.getString("alerter.notify.target"));
model.put("nameConsole", bundle.getString("alerter.notify.console"));
model.put("namePriority", bundle.getString("alerter.notify.priority"));
model.put("priority", bundle.getString("alerter.priority." + alert.getPriority()));
model.put("nameTriggerTime", bundle.getString("alerter.notify.triggerTime"));
model.put("lastTriggerTime", simpleDateFormat.format(new Date(alert.getLastAlarmTime())));
if (CommonConstants.ALERT_STATUS_CODE_RESTORED == alert.getStatus()) {
model.put("nameRestoreTime", bundle.getString("alerter.notify.restoreTime"));
model.put("restoreTime", simpleDateFormat.format(new Date(alert.getFirstAlarmTime())));
}
model.put("consoleUrl", alerterProperties.getConsoleUrl());
model.put("nameContent", bundle.getString("alerter.notify.content"));
model.put("content", alert.getContent());
StringTemplateLoader stringLoader = new StringTemplateLoader();
String templateName = "mailTemplate";
stringLoader.putTemplate(templateName, noticeTemplate.getContent());
cfg.setTemplateLoader(stringLoader);
cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
templateMail = cfg.getTemplate(templateName, Locale.CHINESE);
return FreeMarkerTemplateUtils.processTemplateIntoString(templateMail, model);
}
@EventListener(SystemConfigChangeEvent.class)
public void onEvent(SystemConfigChangeEvent event) {
log.info("{} receive system config change event: {}.", this.getClass().getName(), event.getSource());
this.bundle = ResourceBundleUtil.getBundle("alerter");
}
}

View File

@ -600,7 +600,7 @@
class="tblCell">
<div style="line-height: 150%;">
<span style="font-size: 30px; line-height: 150%;">
<strong >${nameTitle}</strong>
<strong >${title}</strong>
</span>
</div>
</td>
@ -648,7 +648,7 @@
color: #817878;
font-weight: 500;">
<span>
${nameTarget}
${targetLabel}
</span>
</td>
<td><span
@ -659,7 +659,7 @@
<td align="right"
style="padding-right: 10px; color: #817878; font-weight: 500;">
<span >
${nameMonitorId}
${monitorIdLabel}
</span>
</td>
<td>
@ -670,7 +670,7 @@
<td align="right"
style="padding-right: 10px; color: #817878; font-weight: 500;">
<span>
${nameMonitorName}
${monitorNameLabel}
</span>
</td>
<td>
@ -681,7 +681,7 @@
<td align="right"
style="padding-right: 10px; color: #817878; font-weight: 500;">
<span>
${nameMonitorHost}
${monitorHostLabel}
</span>
</td>
<td>
@ -692,7 +692,7 @@
<td align="right"
style="padding-right: 10px; color: #817878; font-weight: 500;">
<span>
${namePriority}
${priorityLabel}
</span>
</td>
<td>
@ -703,19 +703,19 @@
<td align="right"
style="padding-right: 10px; color: #817878; font-weight: 500;">
<span>
${nameTriggerTime}
${triggerTimeLabel}
</span>
</td>
<td><span
>${lastTriggerTime}</span>
>${triggerTime}</span>
</td>
</tr>
<#if nameRestoreTime??>
<#if restoreTime??>
<tr>
<td align="right"
style="padding-right: 10px; color: #817878; font-weight: 500;">
<span>
${nameRestoreTime}
${restoreTimeLabel}
</span>
</td>
<td><span
@ -767,7 +767,7 @@
target="_blank"
style="color:#FFFFFF;text-decoration:none;"
href="${consoleUrl}"
data-link-type="web">${nameConsole}</a></span>
data-link-type="web">${consoleLabel}</a></span>
</td>
</tr>
</tbody>

View File

@ -17,19 +17,17 @@
package org.apache.hertzbeat.manager.component.alerter.impl;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.mail.internet.MimeMessage;
import java.util.Date;
import java.util.Properties;
import java.util.HashMap;
import java.util.Map;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeReceiver;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.manager.dao.GeneralConfigDao;
import org.apache.hertzbeat.manager.service.MailService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -50,17 +48,6 @@ class EmailAlertNotifyHandlerImplTest {
@Mock
private JavaMailSenderImpl javaMailSender;
@Mock
private MailService mailService;
@Mock
private GeneralConfigDao generalConfigDao;
@Mock
private ObjectMapper objectMapper;
private JavaMailSenderImpl sender;
@InjectMocks
private EmailAlertNotifyHandlerImpl emailAlertNotifyHandler;
@ -81,19 +68,31 @@ class EmailAlertNotifyHandlerImplTest {
receiver.setEmail("receiver@example.com");
NoticeTemplate noticeTemplate = new NoticeTemplate();
Alert alert = Alert.builder().build();
noticeTemplate.setId(1L);
noticeTemplate.setName("Email");
noticeTemplate.setContent("""
${targetLabel} : ${target}
<#if (monitorId??)>${monitorIdLabel} : ${monitorId} </#if>
<#if (monitorName??)>${monitorNameLabel} : ${monitorName} </#if>
<#if (monitorHost??)>${monitorHostLabel} : ${monitorHost} </#if>
${priorityLabel} : ${priority}
${triggerTimeLabel} : ${triggerTime}
${contentLabel} : ${content}""");
Alert alert = new Alert();
alert.setId(1L);
alert.setTarget("Mock Target");
Map<String, String> map = new HashMap<>();
map.put(CommonConstants.TAG_MONITOR_ID, "Mock monitor id");
map.put(CommonConstants.TAG_MONITOR_NAME, "Mock monitor name");
map.put(CommonConstants.TAG_MONITOR_HOST, "Mock monitor host");
alert.setTags(map);
alert.setContent("mock content");
alert.setPriority((byte) 0);
alert.setLastAlarmTime(System.currentTimeMillis());
MimeMessage mimeMessage = mock(MimeMessage.class);
when(javaMailSender.createMimeMessage()).thenReturn(mimeMessage);
Properties properties = new Properties();
when(javaMailSender.getJavaMailProperties()).thenReturn(properties);
when(mailService.buildAlertHtmlTemplate(
any(Alert.class),
any(NoticeTemplate.class))
).thenReturn("HTML Content");
emailAlertNotifyHandler.send(receiver, noticeTemplate, alert);
verify(javaMailSender).send(mimeMessage);

View File

@ -1,71 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hertzbeat.manager.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import freemarker.template.TemplateException;
import java.io.IOException;
import java.util.ResourceBundle;
import org.apache.hertzbeat.alert.AlerterProperties;
import org.apache.hertzbeat.common.constants.CommonConstants;
import org.apache.hertzbeat.common.entity.alerter.Alert;
import org.apache.hertzbeat.common.entity.manager.NoticeTemplate;
import org.apache.hertzbeat.manager.service.impl.MailServiceImpl;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
/**
* Test case for {@link MailService}
*/
@ExtendWith(MockitoExtension.class)
class MailServiceTest {
@Spy
@InjectMocks
private MailServiceImpl mailService;
@Mock
private AlerterProperties alerterProperties;
@Mock
private ResourceBundle bundle;
@Test
void buildAlertHtmlTemplate() throws TemplateException, IOException {
Alert alert = new Alert();
NoticeTemplate noticeTemplate = new NoticeTemplate();
alert.setTarget("Test Target");
alert.setContent("Test");
alert.setTriggerTimes(1);
alert.setFirstAlarmTime(System.currentTimeMillis());
alert.setLastAlarmTime(System.currentTimeMillis());
alert.setPriority(CommonConstants.ALERT_PRIORITY_CODE_CRITICAL);
noticeTemplate.setId(1L);
noticeTemplate.setName("test");
noticeTemplate.setContent("result");
assertEquals("result", mailService.buildAlertHtmlTemplate(alert, noticeTemplate));
assertNotNull(mailService.buildAlertHtmlTemplate(alert, noticeTemplate));
}
}

View File

@ -48,12 +48,6 @@
"icon": "anticon-code",
"link": "/setting/define"
},
{
"text": "Prometheus",
"i18n": "menu.monitor.prometheus",
"icon": "anticon-insert-row-below",
"link": "/monitors?app=prometheus"
},
{
"key": "service",
"text": "Service",