mirror of https://github.com/certd/certd
perf: 通知支持钉钉群聊机器人
parent
441b15ed2f
commit
fc8bef5aae
|
@ -0,0 +1,143 @@
|
||||||
|
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
|
||||||
|
|
||||||
|
@IsNotification({
|
||||||
|
name: 'dingtalk',
|
||||||
|
title: '钉钉通知',
|
||||||
|
desc: '钉钉群聊通知',
|
||||||
|
needPlus: true,
|
||||||
|
})
|
||||||
|
// https://open.dingtalk.com/document/orgapp/the-creation-and-installation-of-the-application-robot-in-the?spm=ding_open_doc.document.0.0.242d1563cDgZz3
|
||||||
|
export class DingTalkNotification extends BaseNotification {
|
||||||
|
@NotificationInput({
|
||||||
|
title: 'webhook地址',
|
||||||
|
component: {
|
||||||
|
placeholder: 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxx',
|
||||||
|
},
|
||||||
|
helper: '钉钉APP->群聊->设置->机器人->添加机器人->自定义->[创建机器人->复制webhook地址](https://open.dingtalk.com/document/robots/custom-robot-access)',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
webhook = '';
|
||||||
|
|
||||||
|
@NotificationInput({
|
||||||
|
title: '加签密钥',
|
||||||
|
component: {
|
||||||
|
placeholder: 'SECxxxxxxxxxxxxxxxxxxxxx',
|
||||||
|
},
|
||||||
|
helper: '必须选择一种安全设置,请选择加密密钥',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
secret = '';
|
||||||
|
|
||||||
|
|
||||||
|
@NotificationInput({
|
||||||
|
title: '@用户ID',
|
||||||
|
component: {
|
||||||
|
placeholder: '非必填,填写完一个按回车',
|
||||||
|
name: 'a-select',
|
||||||
|
vModel: 'value',
|
||||||
|
mode: 'tags',
|
||||||
|
multiple: true,
|
||||||
|
open: false,
|
||||||
|
},
|
||||||
|
helper: '填写要@的用户ID',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
atUserIds:string[];
|
||||||
|
|
||||||
|
@NotificationInput({
|
||||||
|
title: '@用户手机号',
|
||||||
|
component: {
|
||||||
|
placeholder: '非必填,填写一个按回车',
|
||||||
|
name: 'a-select',
|
||||||
|
vModel: 'value',
|
||||||
|
mode: 'tags',
|
||||||
|
multiple: true,
|
||||||
|
open: false,
|
||||||
|
},
|
||||||
|
helper: '填写要@的用户的手机号',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
atMobiles:string[];
|
||||||
|
|
||||||
|
|
||||||
|
@NotificationInput({
|
||||||
|
title: '@all',
|
||||||
|
component: {
|
||||||
|
placeholder: '非必填',
|
||||||
|
name: 'a-switch',
|
||||||
|
vModel:"checked"
|
||||||
|
},
|
||||||
|
helper: '是否@所有人',
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
isAtAll:boolean;
|
||||||
|
|
||||||
|
|
||||||
|
async sign(){
|
||||||
|
const timestamp = Date.now();
|
||||||
|
const secret = this.secret;
|
||||||
|
const stringToSign = `${timestamp}\n${secret}`;
|
||||||
|
/**
|
||||||
|
* string_to_sign = '{}\n{}'.format(timestamp, secret)
|
||||||
|
* string_to_sign_enc = string_to_sign.encode('utf-8')
|
||||||
|
* hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
|
||||||
|
* sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
|
||||||
|
*/
|
||||||
|
const crypto = await import('crypto');
|
||||||
|
const hmac = crypto.createHmac('sha256', secret);
|
||||||
|
hmac.update(stringToSign);
|
||||||
|
const sign = encodeURIComponent(Buffer.from(hmac.digest()).toString('base64'));
|
||||||
|
|
||||||
|
return {
|
||||||
|
timestamp,
|
||||||
|
sign,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async send(body: NotificationBody) {
|
||||||
|
if (!this.webhook) {
|
||||||
|
throw new Error('webhook地址不能为空');
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* "msgtype": "text",
|
||||||
|
* "text": {
|
||||||
|
* "content": "hello world"
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
let webhook = this.webhook;
|
||||||
|
if(this.secret){
|
||||||
|
const signRet = await this.sign();
|
||||||
|
webhook = `${webhook}×tamp=${signRet.timestamp}&sign=${signRet.sign}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const at :any= {}
|
||||||
|
if(this.atUserIds && this.atUserIds.length>0){
|
||||||
|
at.atUserIds = this.atUserIds;
|
||||||
|
}
|
||||||
|
if(this.atMobiles && this.atMobiles.length>0){
|
||||||
|
at.atMobiles = this.atMobiles;
|
||||||
|
}
|
||||||
|
if(this.isAtAll){
|
||||||
|
at.isAtAll = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await this.http.request({
|
||||||
|
url: webhook,
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
at: at,
|
||||||
|
text: {
|
||||||
|
content: `· ${body.title}\n· ${body.content}\n· 查看详情: ${body.url}`,
|
||||||
|
},
|
||||||
|
msgtype:"text"
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if(res.errcode>100){
|
||||||
|
throw new Error(`发送失败:${res.errmsg}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue