diff --git a/common/src/main/java/org/dromara/hertzbeat/common/entity/manager/NoticeReceiver.java b/common/src/main/java/org/dromara/hertzbeat/common/entity/manager/NoticeReceiver.java index 434524c1d99..2a3f5ddb38a 100644 --- a/common/src/main/java/org/dromara/hertzbeat/common/entity/manager/NoticeReceiver.java +++ b/common/src/main/java/org/dromara/hertzbeat/common/entity/manager/NoticeReceiver.java @@ -67,8 +67,8 @@ public class NoticeReceiver { @NotNull private String name; - @Schema(title = "Notification information method: 0-SMS 1-Email 2-webhook 3-WeChat Official Account 4-Enterprise WeChat Robot 5-DingTalk Robot 6-FeiShu Robot 7-Telegram Bot 8-SlackWebHook 9-Discord Bot", - description = "通知信息方式: 0-手机短信 1-邮箱 2-webhook 3-微信公众号 4-企业微信机器人 5-钉钉机器人 6-飞书机器人 7-Telegram机器人 8-SlackWebHook 9-Discord机器人", + @Schema(title = "Notification information method: 0-SMS 1-Email 2-webhook 3-WeChat Official Account 4-Enterprise WeChat Robot 5-DingTalk Robot 6-FeiShu Robot 7-Telegram Bot 8-SlackWebHook 9-Discord Bot 10-Enterprise WeChat app message", + description = "通知信息方式: 0-手机短信 1-邮箱 2-webhook 3-微信公众号 4-企业微信机器人 5-钉钉机器人 6-飞书机器人 7-Telegram机器人 8-SlackWebHook 9-Discord机器人 10-企业微信-应用消息", accessMode = READ_WRITE) @Min(0) @NotNull @@ -120,6 +120,21 @@ public class NoticeReceiver { @Length(max = 300) private String slackWebHookUrl; + @Schema(title = "Enterprise weChat message: The notification method is valid for Enterprise WeChat app message", + description = "企业信息 : 通知方式为Enterprise WeChat app message有效", + example = "ww1a603432123d0dc1", accessMode = READ_WRITE) + private String corpId; + + @Schema(title = "Enterprise weChat appId: The notification method is valid for Enterprise WeChat app message", + description = "企业微信应用id : 通知方式为Enterprise WeChat app message有效", + example = "1000001", accessMode = READ_WRITE) + private Integer agentId; + + @Schema(title = "Enterprise weChat secret: The notification method is valid for Enterprise WeChat app message", + description = "企业微信应用secret : 通知方式为Enterprise WeChat app message有效", + example = "oUydwn92ey0lnuY02MixNa57eNK-20dJn5NEOG-u2uE", accessMode = READ_WRITE) + private String appSecret; + @Schema(title = "Discord channel id: The notification method is valid for Discord", description = "Discord 频道id: 通知方式为Discord有效", example = "1065303416030642266", accessMode = READ_WRITE) diff --git a/manager/src/main/java/org/dromara/hertzbeat/manager/component/alerter/impl/WeChatAppAlertNotifyHandlerImpl.java b/manager/src/main/java/org/dromara/hertzbeat/manager/component/alerter/impl/WeChatAppAlertNotifyHandlerImpl.java new file mode 100644 index 00000000000..1428e8bcc4f --- /dev/null +++ b/manager/src/main/java/org/dromara/hertzbeat/manager/component/alerter/impl/WeChatAppAlertNotifyHandlerImpl.java @@ -0,0 +1,84 @@ +package org.dromara.hertzbeat.manager.component.alerter.impl; + +import com.alibaba.fastjson.JSON; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.hertzbeat.common.entity.alerter.Alert; +import org.dromara.hertzbeat.common.entity.manager.NoticeReceiver; +import org.dromara.hertzbeat.manager.component.alerter.AlertNotifyHandler; +import org.dromara.hertzbeat.manager.pojo.dto.WeChatAppDTO; +import org.dromara.hertzbeat.manager.pojo.dto.WeChatAppReq; +import org.dromara.hertzbeat.manager.support.exception.AlertNoticeException; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import java.util.Objects; + +/** + * @description: + * @author: hdd + * @create: 2023/04/04 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class WeChatAppAlertNotifyHandlerImpl implements AlertNotifyHandler { + + /** + * send weChat app message url + */ + private static final String APP_MESSAGE_URL = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=%s"; + + /** + * get access_token url + */ + private static final String SECRET_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=%s&corpsecret=%s"; + + /** + * 应用消息发送对象 + */ + private static final String DEFAULT_ALL = "@all"; + + /** + * send message type + */ + private static final String DEFAULT_TYPE = "text"; + + private final RestTemplate restTemplate; + + @Override + public void send(NoticeReceiver receiver, Alert alert) throws AlertNoticeException { + String corpId = receiver.getCorpId(); + Integer agentId = receiver.getAgentId(); + String appSecret = receiver.getAppSecret(); + + try { + ResponseEntity entityResponse = restTemplate.getForEntity(String.format(SECRET_URL, corpId, appSecret), WeChatAppReq.class); + if (Objects.nonNull(entityResponse.getBody())) { + String accessToken = entityResponse.getBody().getAccessToken(); + WeChatAppDTO.TextDTO textDTO = new WeChatAppDTO.TextDTO(); + textDTO.setContent(JSON.toJSONString(alert)); + WeChatAppDTO weChatAppDTO = WeChatAppDTO.builder() + .toUser(DEFAULT_ALL) + .msgType(DEFAULT_TYPE) + .agentId(agentId) + .text(textDTO) + .build(); + ResponseEntity response = restTemplate.postForEntity(String.format(APP_MESSAGE_URL, accessToken), weChatAppDTO, WeChatAppReq.class); + if (Objects.nonNull(response.getBody()) && !Objects.equals(response.getBody().getErrCode(), 0)) { + log.warn("Send Enterprise WeChat App Error: {} Failed: {}", receiver.getHookUrl(), response.getBody().getErrMsg()); + throw new AlertNoticeException("Http StatusCode " + response.getStatusCode()); + } + } + } catch (Exception e) { + throw new AlertNoticeException("[WebHook Notify Error] " + e.getMessage()); + } + } + + @Override + public byte type() { + return 10; + } + +} diff --git a/manager/src/main/java/org/dromara/hertzbeat/manager/pojo/dto/WeChatAppDTO.java b/manager/src/main/java/org/dromara/hertzbeat/manager/pojo/dto/WeChatAppDTO.java new file mode 100644 index 00000000000..a3817f0a35b --- /dev/null +++ b/manager/src/main/java/org/dromara/hertzbeat/manager/pojo/dto/WeChatAppDTO.java @@ -0,0 +1,47 @@ +package org.dromara.hertzbeat.manager.pojo.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: + * @author: hdd + * @create: 2023/04/05 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class WeChatAppDTO { + + @JsonProperty(value = "touser") + private String toUser; + + @JsonProperty(value = "toparty") + private String toParty; + + @JsonProperty(value = "totag") + private String toTag; + + @JsonProperty(value = "msgtype") + private String msgType; + + @JsonProperty(value = "agentid") + private Integer agentId; + + + private TextDTO text; + + + @Data + public static class TextDTO { + /** + * 消息内容 + */ + private String content; + } + +} diff --git a/manager/src/main/java/org/dromara/hertzbeat/manager/pojo/dto/WeChatAppReq.java b/manager/src/main/java/org/dromara/hertzbeat/manager/pojo/dto/WeChatAppReq.java new file mode 100644 index 00000000000..9c0c10762d0 --- /dev/null +++ b/manager/src/main/java/org/dromara/hertzbeat/manager/pojo/dto/WeChatAppReq.java @@ -0,0 +1,26 @@ +package org.dromara.hertzbeat.manager.pojo.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: + * @author: hdd + * @create: 2023/04/05 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class WeChatAppReq { + + @JsonProperty(value = "errcode") + private Integer errCode; + + @JsonProperty(value = "errmsg") + private String errMsg; + + @JsonProperty(value = "access_token") + private String accessToken; +} diff --git a/manager/src/test/java/org/dromara/hertzbeat/manager/component/alerter/impl/WeChatAppAlertNotifyHandlerImplTest.java b/manager/src/test/java/org/dromara/hertzbeat/manager/component/alerter/impl/WeChatAppAlertNotifyHandlerImplTest.java new file mode 100644 index 00000000000..2cdffa08c7a --- /dev/null +++ b/manager/src/test/java/org/dromara/hertzbeat/manager/component/alerter/impl/WeChatAppAlertNotifyHandlerImplTest.java @@ -0,0 +1,22 @@ +package org.dromara.hertzbeat.manager.component.alerter.impl; + +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.web.client.RestTemplate; + +/** + * @description: + * @author: hdd + * @create: 2023/04/05 + */ +public class WeChatAppAlertNotifyHandlerImplTest { + + + @InjectMocks + private WeChatAppAlertNotifyHandlerImpl weChatAppAlertNotifyHandler; + + @Mock + private RestTemplate restTemplate; + + +} diff --git a/web-app/src/app/pojo/NoticeReceiver.ts b/web-app/src/app/pojo/NoticeReceiver.ts index 744c34b47dd..b71b84a766b 100644 --- a/web-app/src/app/pojo/NoticeReceiver.ts +++ b/web-app/src/app/pojo/NoticeReceiver.ts @@ -1,7 +1,7 @@ export class NoticeReceiver { id!: number; name!: string; - // 通知信息方式: 0-手机短信 1-邮箱 2-webhook 3-微信公众号 4-企业微信机器人 5-钉钉机器人 6-飞书机器人 7-Telegram机器人 8-SlackWebHook 9-Discord机器人 + // 通知信息方式: 0-手机短信 1-邮箱 2-webhook 3-微信公众号 4-企业微信机器人 5-钉钉机器人 6-飞书机器人 7-Telegram机器人 8-SlackWebHook 9-Discord机器人 10-企业微信应用消息 type: number = 1; phone!: string; email!: string; @@ -13,6 +13,9 @@ export class NoticeReceiver { hookUrl!: string; wechatId!: string; accessToken!: string; + corpId!: string; + agentId!: number; + appSecret!: string; creator!: string; modifier!: string; gmtCreate!: number; diff --git a/web-app/src/app/routes/alert/alert-notice/alert-notice.component.html b/web-app/src/app/routes/alert/alert-notice/alert-notice.component.html index c27cf31b921..f881fd3f244 100644 --- a/web-app/src/app/routes/alert/alert-notice/alert-notice.component.html +++ b/web-app/src/app/routes/alert/alert-notice/alert-notice.component.html @@ -94,6 +94,10 @@ {{ 'alert.notice.type.discord' | i18n }} + + + {{ 'alert.notice.type.weChatApp' | i18n }} + {{ data.phone }} @@ -106,6 +110,7 @@ {{ data.tgBotToken }}
{{ data.tgUserId }}
{{ data.slackWebHookUrl }} {{ data.discordChannelId }}
{{ data.discordBotToken }}
+ {{ data.corpId }}
{{ data.agentId }}
{{ data.appSecret }}
{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date : 'YYYY-MM-dd HH:mm:ss' }} @@ -236,6 +241,7 @@ + @@ -329,6 +335,30 @@ + + + {{ 'alert.notice.type.weChatApp-corpId' | i18n }} + + + + + + + + {{ 'alert.notice.type.weChatApp-agentId' | i18n }} + + + + + + + + {{ 'alert.notice.type.weChatApp-appSecret' | i18n }} + + + + +