增加飞书机器人通知

This commit is contained in:
whyour 2022-10-29 16:41:37 +08:00
parent 2789119882
commit 6385e053ae
5 changed files with 213 additions and 204 deletions

View File

@ -15,6 +15,7 @@ export enum NotificationMode {
'iGot' = 'iGot', 'iGot' = 'iGot',
'pushPlus' = 'pushPlus', 'pushPlus' = 'pushPlus',
'email' = 'email', 'email' = 'email',
'feishu' = 'feishu',
'webhook' = 'webhook', 'webhook' = 'webhook',
} }
@ -102,7 +103,14 @@ export class WebhookNotification extends NotificationBaseInfo {
public webhookBody: string = ''; public webhookBody: string = '';
public webhookUrl: string = ''; public webhookUrl: string = '';
public webhookMethod: 'GET' | 'POST' | 'PUT' = 'GET'; public webhookMethod: 'GET' | 'POST' | 'PUT' = 'GET';
public webhookContentType: 'application/json' | 'multipart/form-data' | 'application/x-www-form-urlencoded' = 'application/json'; public webhookContentType:
| 'application/json'
| 'multipart/form-data'
| 'application/x-www-form-urlencoded' = 'application/json';
}
export class LarkNotification extends NotificationBaseInfo {
public larkKey = '';
} }
export interface NotificationInfo export interface NotificationInfo
@ -120,4 +128,5 @@ export interface NotificationInfo
IGotNotification, IGotNotification,
PushPlusNotification, PushPlusNotification,
EmailNotification, EmailNotification,
WebhookNotification {} WebhookNotification,
LarkNotification {}

View File

@ -29,6 +29,7 @@ export default class NotificationService {
['pushPlus', this.pushPlus], ['pushPlus', this.pushPlus],
['email', this.email], ['email', this.email],
['webhook', this.webhook], ['webhook', this.webhook],
['lark', this.lark],
]); ]);
private title = ''; private title = '';
@ -37,9 +38,9 @@ export default class NotificationService {
private gotOption = { private gotOption = {
timeout: 30000, timeout: 30000,
retry: 1, retry: 1,
} };
constructor(@Inject('logger') private logger: winston.Logger) { } constructor(@Inject('logger') private logger: winston.Logger) {}
public async notify( public async notify(
title: string, title: string,
@ -180,7 +181,8 @@ export default class NotificationService {
telegramBotUserId, telegramBotUserId,
} = this.params; } = this.params;
const authStr = telegramBotProxyAuth ? `${telegramBotProxyAuth}@` : ''; const authStr = telegramBotProxyAuth ? `${telegramBotProxyAuth}@` : '';
const url = `https://${telegramBotApiHost ? telegramBotApiHost : 'api.telegram.org' const url = `https://${
telegramBotApiHost ? telegramBotApiHost : 'api.telegram.org'
}/bot${telegramBotToken}/sendMessage`; }/bot${telegramBotToken}/sendMessage`;
let agent; let agent;
if (telegramBotProxyHost && telegramBotProxyPort) { if (telegramBotProxyHost && telegramBotProxyPort) {
@ -324,30 +326,30 @@ export default class NotificationService {
private async aibotk() { private async aibotk() {
const { aibotkKey, aibotkType, aibotkName } = this.params; const { aibotkKey, aibotkType, aibotkName } = this.params;
let url = '' let url = '';
let json = {} let json = {};
switch (aibotkType) { switch (aibotkType) {
case 'room': case 'room':
url = 'https://api-bot.aibotk.com/openapi/v1/chat/room' url = 'https://api-bot.aibotk.com/openapi/v1/chat/room';
json = { json = {
apiKey: `${aibotkKey}`, apiKey: `${aibotkKey}`,
roomName: `${aibotkName}`, roomName: `${aibotkName}`,
message: { message: {
type: 1, type: 1,
content: `【青龙快讯】\n\n${this.title}\n${this.content}` content: `【青龙快讯】\n\n${this.title}\n${this.content}`,
} },
} };
break; break;
case 'contact': case 'contact':
url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact' url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact';
json = { json = {
apiKey: `${aibotkKey}`, apiKey: `${aibotkKey}`,
name: `${aibotkName}`, name: `${aibotkName}`,
message: { message: {
type: 1, type: 1,
content: `【青龙快讯】\n\n${this.title}\n${this.content}` content: `【青龙快讯】\n\n${this.title}\n${this.content}`,
} },
} };
break; break;
} }
@ -355,9 +357,10 @@ export default class NotificationService {
.post(url, { .post(url, {
...this.gotOption, ...this.gotOption,
json: { json: {
...json ...json,
} },
}).json(); })
.json();
return res.code === 0; return res.code === 0;
} }
@ -394,6 +397,21 @@ export default class NotificationService {
return res.code === 200; return res.code === 200;
} }
private async lark() {
const { larkKey } = this.params;
const res: any = await got
.post(`https://open.feishu.cn/open-apis/bot/v2/hook/${larkKey}`, {
...this.gotOption,
json: {
msg_type: 'text',
content: { text: `${this.title}\n\n${this.content}` },
},
headers: { 'Content-Type': 'application/json' },
})
.json();
return res.StatusCode === 0;
}
private async email() { private async email() {
const { emailPass, emailService, emailUser } = this.params; const { emailPass, emailService, emailUser } = this.params;
const transporter = nodemailer.createTransport({ const transporter = nodemailer.createTransport({
@ -417,10 +435,18 @@ export default class NotificationService {
} }
private async webhook() { private async webhook() {
const { webhookUrl, webhookBody, webhookHeaders, webhookMethod, webhookContentType } = const {
this.params; webhookUrl,
webhookBody,
webhookHeaders,
webhookMethod,
webhookContentType,
} = this.params;
const { formatBody, formatUrl } = this.formatNotifyContent(webhookUrl, webhookBody); const { formatBody, formatUrl } = this.formatNotifyContent(
webhookUrl,
webhookBody,
);
if (!formatUrl && !formatBody) { if (!formatUrl && !formatBody) {
return false; return false;
} }
@ -432,8 +458,8 @@ export default class NotificationService {
headers, headers,
...this.gotOption, ...this.gotOption,
allowGetBody: true, allowGetBody: true,
...bodyParam ...bodyParam,
} };
const res = await got(formatUrl, options); const res = await got(formatUrl, options);
return String(res.statusCode).startsWith('20'); return String(res.statusCode).startsWith('20');
} }
@ -457,8 +483,12 @@ export default class NotificationService {
} }
return { return {
formatUrl: url.replaceAll('$title', encodeURIComponent(this.title)).replaceAll('$content', encodeURIComponent(this.content)), formatUrl: url
formatBody: body.replaceAll('$title', this.title).replaceAll('$content', this.content), .replaceAll('$title', encodeURIComponent(this.title))
} .replaceAll('$content', encodeURIComponent(this.content)),
formatBody: body
.replaceAll('$title', this.title)
.replaceAll('$content', this.content),
};
} }
} }

View File

@ -110,7 +110,6 @@ let PUSH_PLUS_USER = '';
let QQ_SKEY = ''; let QQ_SKEY = '';
let QQ_MODE = ''; let QQ_MODE = '';
// =======================================智能微秘书设置区域======================================= // =======================================智能微秘书设置区域=======================================
//官方文档http://wechat.aibotk.com/docs/about //官方文档http://wechat.aibotk.com/docs/about
//AIBOTK_KEY 填写智能微秘书个人中心的apikey //AIBOTK_KEY 填写智能微秘书个人中心的apikey
@ -120,6 +119,11 @@ let AIBOTK_KEY = '';
let AIBOTK_TYPE = ''; let AIBOTK_TYPE = '';
let AIBOTK_NAME = ''; let AIBOTK_NAME = '';
// =======================================飞书机器人设置区域=======================================
//官方文档https://www.feishu.cn/hc/zh-CN/articles/360024984973
//FSKEY 飞书机器人的 FSKEY
let FSKEY = '';
//==========================云端环境变量的判断与接收========================= //==========================云端环境变量的判断与接收=========================
if (process.env.GOTIFY_URL) { if (process.env.GOTIFY_URL) {
GOTIFY_URL = process.env.GOTIFY_URL; GOTIFY_URL = process.env.GOTIFY_URL;
@ -230,14 +234,19 @@ if (process.env.PUSH_PLUS_TOKEN) {
if (process.env.PUSH_PLUS_USER) { if (process.env.PUSH_PLUS_USER) {
PUSH_PLUS_USER = process.env.PUSH_PLUS_USER; PUSH_PLUS_USER = process.env.PUSH_PLUS_USER;
} }
if(process.env.AIBOTK_KEY) {
AIBOTK_KEY = process.env.AIBOTK_KEY if (process.env.AIBOTK_KEY) {
AIBOTK_KEY = process.env.AIBOTK_KEY;
} }
if(process.env.AIBOTK_TYPE) { if (process.env.AIBOTK_TYPE) {
AIBOTK_TYPE = process.env.AIBOTK_TYPE AIBOTK_TYPE = process.env.AIBOTK_TYPE;
} }
if(process.env.AIBOTK_NAME) { if (process.env.AIBOTK_NAME) {
AIBOTK_NAME = process.env.AIBOTK_NAME AIBOTK_NAME = process.env.AIBOTK_NAME;
}
if (process.env.FSKEY) {
FSKEY = process.env.FSKEY;
} }
//==========================云端环境变量的判断与接收========================= //==========================云端环境变量的判断与接收=========================
@ -275,6 +284,7 @@ async function sendNotify(
ChatNotify(text, desp), //synolog chat ChatNotify(text, desp), //synolog chat
PushDeerNotify(text, desp), //PushDeer PushDeerNotify(text, desp), //PushDeer
aibotkNotify(text, desp), //智能微秘书 aibotkNotify(text, desp), //智能微秘书
fsBotNotify(text, desp), //飞书机器人
]); ]);
} }
@ -315,7 +325,7 @@ function gotifyNotify(text, desp) {
}); });
} }
function gobotNotify(text, desp, time = 2100) { function gobotNotify(text, desp) {
return new Promise((resolve) => { return new Promise((resolve) => {
if (GOBOT_URL) { if (GOBOT_URL) {
const options = { const options = {
@ -326,7 +336,6 @@ function gobotNotify(text, desp, time = 2100) {
}, },
timeout, timeout,
}; };
setTimeout(() => {
$.post(options, (err, resp, data) => { $.post(options, (err, resp, data) => {
try { try {
if (err) { if (err) {
@ -339,9 +348,7 @@ function gobotNotify(text, desp, time = 2100) {
} else if (data.retcode === 100) { } else if (data.retcode === 100) {
console.log(`go-cqhttp发送通知消息异常: ${data.errmsg}\n`); console.log(`go-cqhttp发送通知消息异常: ${data.errmsg}\n`);
} else { } else {
console.log( console.log(`go-cqhttp发送通知消息异常\n${JSON.stringify(data)}`);
`go-cqhttp发送通知消息异常\n${JSON.stringify(data)}`,
);
} }
} }
} catch (e) { } catch (e) {
@ -350,14 +357,13 @@ function gobotNotify(text, desp, time = 2100) {
resolve(data); resolve(data);
} }
}); });
}, time);
} else { } else {
resolve(); resolve();
} }
}); });
} }
function serverNotify(text, desp, time = 2100) { function serverNotify(text, desp) {
return new Promise((resolve) => { return new Promise((resolve) => {
if (SCKEY) { if (SCKEY) {
//微信server酱推送通知一个\n不会换行需要两个\n才能换行故做此替换 //微信server酱推送通知一个\n不会换行需要两个\n才能换行故做此替换
@ -372,7 +378,6 @@ function serverNotify(text, desp, time = 2100) {
}, },
timeout, timeout,
}; };
setTimeout(() => {
$.post(options, (err, resp, data) => { $.post(options, (err, resp, data) => {
try { try {
if (err) { if (err) {
@ -387,9 +392,7 @@ function serverNotify(text, desp, time = 2100) {
// 一分钟内发送相同的内容会触发 // 一分钟内发送相同的内容会触发
console.log(`server酱发送通知消息异常: ${data.errmsg}\n`); console.log(`server酱发送通知消息异常: ${data.errmsg}\n`);
} else { } else {
console.log( console.log(`server酱发送通知消息异常\n${JSON.stringify(data)}`);
`server酱发送通知消息异常\n${JSON.stringify(data)}`,
);
} }
} }
} catch (e) { } catch (e) {
@ -398,7 +401,6 @@ function serverNotify(text, desp, time = 2100) {
resolve(data); resolve(data);
} }
}); });
}, time);
} else { } else {
resolve(); resolve();
} }
@ -418,9 +420,7 @@ function PushDeerNotify(text, desp) {
}, },
timeout, timeout,
}; };
$.post( $.post(options, (err, resp, data) => {
options,
(err, resp, data) => {
try { try {
if (err) { if (err) {
console.log('发送通知调用API失败\n'); console.log('发送通知调用API失败\n');
@ -434,9 +434,7 @@ function PushDeerNotify(text, desp) {
) { ) {
console.log('PushDeer发送通知消息成功🎉\n'); console.log('PushDeer发送通知消息成功🎉\n');
} else { } else {
console.log( console.log(`PushDeer发送通知消息异常\n${JSON.stringify(data)}`);
`PushDeer发送通知消息异常\n${JSON.stringify(data)}`,
);
} }
} }
} catch (e) { } catch (e) {
@ -444,9 +442,7 @@ function PushDeerNotify(text, desp) {
} finally { } finally {
resolve(data); resolve(data);
} }
}, });
time,
);
} else { } else {
resolve(); resolve();
} }
@ -490,83 +486,6 @@ function ChatNotify(text, desp) {
}); });
} }
function CoolPush(text, desp) {
return new Promise((resolve) => {
if (QQ_SKEY) {
let options = {
url: `https://push.xuthus.cc/${QQ_MODE}/${QQ_SKEY}`,
headers: {
'Content-Type': 'application/json',
},
};
// 已知敏感词
text = text.replace(/京豆/g, '豆豆');
desp = desp.replace(/京豆/g, '');
desp = desp.replace(/🐶/g, '');
desp = desp.replace(/红包/g, 'H包');
switch (QQ_MODE) {
case 'email':
options.json = {
t: text,
c: desp,
};
break;
default:
options.body = `${text}\n\n${desp}`;
}
let pushMode = function (t) {
switch (t) {
case 'send':
return '个人';
case 'group':
return 'QQ群';
case 'wx':
return '微信';
case 'ww':
return '企业微信';
case 'email':
return '邮件';
default:
return '未知方式';
}
};
$.post(options, (err, resp, data) => {
try {
if (err) {
console.log(`发送${pushMode(QQ_MODE)}通知调用API失败\n`);
console.log(err);
} else {
data = JSON.parse(data);
if (data.code === 200) {
console.log(`酷推发送${pushMode(QQ_MODE)}通知消息成功🎉\n`);
} else if (data.code === 400) {
console.log(
`QQ酷推(Cool Push)发送${pushMode(QQ_MODE)}推送失败:${
data.msg
}\n`,
);
} else if (data.code === 503) {
console.log(`QQ酷推出错${data.message}${data.data}\n`);
} else {
console.log(`酷推推送异常: ${JSON.stringify(data)}`);
}
}
} catch (e) {
$.logErr(e, resp);
} finally {
resolve(data);
}
});
} else {
resolve();
}
});
}
function BarkNotify(text, desp, params = {}) { function BarkNotify(text, desp, params = {}) {
return new Promise((resolve) => { return new Promise((resolve) => {
if (BARK_PUSH) { if (BARK_PUSH) {
@ -669,7 +588,7 @@ function ddBotNotify(text, desp) {
json: { json: {
msgtype: 'text', msgtype: 'text',
text: { text: {
content: ` ${text}\n\n${desp}`, content: `${text}\n\n${desp}`,
}, },
}, },
headers: { headers: {
@ -736,7 +655,7 @@ function qywxBotNotify(text, desp) {
json: { json: {
msgtype: 'text', msgtype: 'text',
text: { text: {
content: ` ${text}\n\n${desp}`, content: `${text}\n\n${desp}`,
}, },
}, },
headers: { headers: {
@ -1005,31 +924,31 @@ function pushPlusNotify(text, desp) {
function aibotkNotify(text, desp) { function aibotkNotify(text, desp) {
return new Promise((resolve) => { return new Promise((resolve) => {
if(AIBOTK_KEY&&AIBOTK_TYPE&&AIBOTK_NAME) { if (AIBOTK_KEY && AIBOTK_TYPE && AIBOTK_NAME) {
let json = {}; let json = {};
let url = ''; let url = '';
switch (AIBOTK_TYPE) { switch (AIBOTK_TYPE) {
case 'room': case 'room':
url = 'https://api-bot.aibotk.com/openapi/v1/chat/room' url = 'https://api-bot.aibotk.com/openapi/v1/chat/room';
json = { json = {
apiKey: `${AIBOTK_KEY}`, apiKey: `${AIBOTK_KEY}`,
roomName: `${AIBOTK_NAME}`, roomName: `${AIBOTK_NAME}`,
message: { message: {
type: 1, type: 1,
content: `【青龙快讯】\n\n${text}\n${desp}` content: `【青龙快讯】\n\n${text}\n${desp}`,
} },
} };
break; break;
case 'contact': case 'contact':
url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact' url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact';
json = { json = {
apiKey: `${AIBOTK_KEY}`, apiKey: `${AIBOTK_KEY}`,
name: `${AIBOTK_NAME}`, name: `${AIBOTK_NAME}`,
message: { message: {
type: 1, type: 1,
content: `【青龙快讯】\n\n${text}\n${desp}` content: `【青龙快讯】\n\n${text}\n${desp}`,
} },
} };
break; break;
} }
const options = { const options = {
@ -1060,7 +979,43 @@ function aibotkNotify(text, desp) {
} }
}); });
} }
}) });
}
function fsBotNotify(text, desp) {
return new Promise((resolve) => {
if (FSKEY) {
const options = {
url: `https://open.feishu.cn/open-apis/bot/v2/hook/${FSKEY}`,
json: { msg_type: 'text', content: { text: `${title}\n\n${content}` } },
headers: {
'Content-Type': 'application/json',
},
timeout,
};
$.post(options, (err, resp, data) => {
try {
if (err) {
console.log('发送通知调用API失败\n');
console.log(err);
} else {
data = JSON.parse(data);
if (data.StatusCode === 0) {
console.log('飞书发送通知消息成功🎉\n');
} else {
console.log(`${data.msg}\n`);
}
}
} catch (e) {
$.logErr(e, resp);
} finally {
resolve(data);
}
});
} else {
resolve();
}
});
} }
module.exports = { module.exports = {

View File

@ -93,6 +93,7 @@ export default {
{ value: 'pushPlus', label: 'PushPlus' }, { value: 'pushPlus', label: 'PushPlus' },
{ value: 'chat', label: '群辉chat' }, { value: 'chat', label: '群辉chat' },
{ value: 'email', label: '邮箱' }, { value: 'email', label: '邮箱' },
{ value: 'lark', label: '飞书机器人' },
{ value: 'webhook', label: '自定义通知' }, { value: 'webhook', label: '自定义通知' },
{ value: 'closed', label: '已关闭' }, { value: 'closed', label: '已关闭' },
], ],
@ -208,7 +209,10 @@ export default {
tip: '发送的目标,群组或者好友', tip: '发送的目标,群组或者好友',
required: true, required: true,
placeholder: '请输入要发送的目标', placeholder: '请输入要发送的目标',
items: [{ value: 'room', label: '群聊' }, { value: 'contact', label: '好友' }], items: [
{ value: 'room', label: '群聊' },
{ value: 'contact', label: '好友' },
],
}, },
{ {
label: 'aibotkName', label: 'aibotkName',
@ -234,6 +238,13 @@ export default {
tip: '一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)', tip: '一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)',
}, },
], ],
lark: [
{
label: 'larkKey',
tip: '飞书群组机器人https://www.feishu.cn/hc/zh-CN/articles/360024984973',
required: true,
},
],
email: [ email: [
{ {
label: 'emailService', label: 'emailService',
@ -254,7 +265,11 @@ export default {
label: 'webhookContentType', label: 'webhookContentType',
tip: '请求头Content-Type', tip: '请求头Content-Type',
required: true, required: true,
items: [{ value: 'application/json' }, { value: 'multipart/form-data' }, { value: 'application/x-www-form-urlencoded' }], items: [
{ value: 'application/json' },
{ value: 'multipart/form-data' },
{ value: 'application/x-www-form-urlencoded' },
],
}, },
{ {
label: 'webhookUrl', label: 'webhookUrl',