Skip to content

Commit

Permalink
[task#736]Add enterprise WeChat application notifications for alerts (#…
Browse files Browse the repository at this point in the history
…844)

  [manage]Add enterprise WeChat application notifications for alerts

Co-authored-by: hudongdong <hudongdong9406@zto.com>
  • Loading branch information
hudongdong129 and hudongdong authored Apr 6, 2023
1 parent dde9a91 commit 4291624
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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<WeChatAppReq> 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<WeChatAppReq> 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;
}

}
Original file line number Diff line number Diff line change
@@ -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;
}

}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;


}
5 changes: 4 additions & 1 deletion web-app/src/app/pojo/NoticeReceiver.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>{{ 'alert.notice.type.discord' | i18n }}</span>
</nz-tag>
<nz-tag *ngIf="data.type == 10" nzColor="orange">
<i nz-icon nzType="notification" nzTheme="outline"></i>
<span>{{ 'alert.notice.type.weChatApp' | i18n }}</span>
</nz-tag>
</td>
<td nzAlign="center">
<span *ngIf="data.type == 0">{{ data.phone }}</span>
Expand All @@ -106,6 +110,7 @@
<span *ngIf="data.type == 7">{{ data.tgBotToken }}<br />{{ data.tgUserId }}</span>
<span *ngIf="data.type == 8">{{ data.slackWebHookUrl }}</span>
<span *ngIf="data.type == 9">{{ data.discordChannelId }}<br />{{ data.discordBotToken }}</span>
<span *ngIf="data.type == 10">{{ data.corpId }}<br />{{ data.agentId }}<br />{{ data.appSecret }}</span>
</td>
<td nzAlign="center">{{ (data.gmtUpdate ? data.gmtUpdate : data.gmtCreate) | date : 'YYYY-MM-dd HH:mm:ss' }}</td>
<td nzAlign="center">
Expand Down Expand Up @@ -236,6 +241,7 @@
<nz-option [nzValue]="5" [nzLabel]="'alert.notice.type.ding' | i18n"></nz-option>
<nz-option [nzValue]="6" [nzLabel]="'alert.notice.type.fei-shu' | i18n"></nz-option>
<nz-option [nzValue]="7" [nzLabel]="'alert.notice.type.telegram-bot' | i18n"></nz-option>
<nz-option [nzValue]="10" [nzLabel]="'alert.notice.type.weChatApp' | i18n"></nz-option>
</nz-select>
</nz-form-control>
</nz-form-item>
Expand Down Expand Up @@ -329,6 +335,30 @@
<input [(ngModel)]="receiver.discordChannelId" nz-input [required]="receiver.type === 9" name="discordChannelId" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 10">
<nz-form-label [nzSpan]="7" nzFor="corpId" [nzRequired]="receiver.type === 10">
{{ 'alert.notice.type.weChatApp-corpId' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.wechatId" nz-input [required]="receiver.type === 10" name="corpId" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 10">
<nz-form-label [nzSpan]="7" nzFor="agentId" [nzRequired]="receiver.type === 10">
{{ 'alert.notice.type.weChatApp-agentId' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.agentId" nz-input [required]="receiver.type === 10" name="agentId" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item *ngIf="receiver.type === 10">
<nz-form-label [nzSpan]="7" nzFor="appSecret" [nzRequired]="receiver.type === 10">
{{ 'alert.notice.type.weChatApp-appSecret' | i18n }}
</nz-form-label>
<nz-form-control [nzSpan]="12" [nzErrorTip]="'validation.required' | i18n">
<input [(ngModel)]="receiver.appSecret" nz-input [required]="receiver.type === 10" name="appSecret" type="text" />
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-control [nzOffset]="7" [nzSpan]="12">
<button nz-button nzDanger nzType="primary" [nzLoading]="isSendTestButtonLoading" (click)="onSendAlertTestMsg()">
Expand Down
4 changes: 4 additions & 0 deletions web-app/src/assets/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@
"alert.notice.type.discord": "Discord Bot",
"alert.notice.type.discord-bot-token": "Discord Bot Token",
"alert.notice.type.discord-channel-id": "Discord Channel ID",
"alert.notice.type.weChatApp": "Enterprise WeChat app",
"alert.notice.type.weChatApp-corpId": "Enterprise WeChat ID",
"alert.notice.type.weChatApp-agentId": "Enterprise App ID",
"alert.notice.type.weChatApp-appSecret": "Enterprise App Secret",
"alert.notice.rule": "Alert Notice Policy",
"alert.notice.rule.new": "New Notice Policy",
"alert.notice.rule.edit": "Edit Notice Policy",
Expand Down
4 changes: 4 additions & 0 deletions web-app/src/assets/i18n/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@
"alert.notice.type.discord": "Discord机器人",
"alert.notice.type.discord-bot-token": "Discord Bot Token",
"alert.notice.type.discord-channel-id": "Discord频道ID",
"alert.notice.type.weChatApp": "企业微信应用",
"alert.notice.type.weChatApp-corpId": "企业id",
"alert.notice.type.weChatApp-agentId": "企业应用id",
"alert.notice.type.weChatApp-appSecret": "企业应用secret",
"alert.notice.rule": "告警通知策略",
"alert.notice.rule.new": "新增通知策略",
"alert.notice.rule.edit": "编辑通知策略",
Expand Down
4 changes: 4 additions & 0 deletions web-app/src/assets/i18n/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@
"alert.notice.type.discord": "Discord機器人",
"alert.notice.type.discord-bot-token": "Discord Bot Token",
"alert.notice.type.discord-channel-id": "Discord頻道ID",
"alert.notice.type.weChatApp": "企業微信應用",
"alert.notice.type.weChatApp-corpId": "企業id",
"alert.notice.type.weChatApp-agentId": "企業應用id",
"alert.notice.type.weChatApp-appSecret": "企業應用secret",
"alert.notice.rule": "告警通知策略",
"alert.notice.rule.new": "新增通知策略",
"alert.notice.rule.edit": "編輯通知策略",
Expand Down

0 comments on commit 4291624

Please sign in to comment.