From 6385e053aefbada193e378a253be4c7dbc2cc6f4 Mon Sep 17 00:00:00 2001 From: whyour Date: Sat, 29 Oct 2022 16:41:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=A3=9E=E4=B9=A6=E6=9C=BA?= =?UTF-8?q?=E5=99=A8=E4=BA=BA=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/data/notify.ts | 13 +- back/services/notify.ts | 84 ++++++++---- sample/notify.js | 295 +++++++++++++++++----------------------- sample/notify.py | 6 +- src/utils/config.ts | 19 ++- 5 files changed, 213 insertions(+), 204 deletions(-) diff --git a/back/data/notify.ts b/back/data/notify.ts index 865b598f..45cd587f 100644 --- a/back/data/notify.ts +++ b/back/data/notify.ts @@ -15,6 +15,7 @@ export enum NotificationMode { 'iGot' = 'iGot', 'pushPlus' = 'pushPlus', 'email' = 'email', + 'feishu' = 'feishu', 'webhook' = 'webhook', } @@ -102,7 +103,14 @@ export class WebhookNotification extends NotificationBaseInfo { public webhookBody: string = ''; public webhookUrl: string = ''; 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 @@ -120,4 +128,5 @@ export interface NotificationInfo IGotNotification, PushPlusNotification, EmailNotification, - WebhookNotification {} + WebhookNotification, + LarkNotification {} diff --git a/back/services/notify.ts b/back/services/notify.ts index 56c02f90..727e5a5a 100644 --- a/back/services/notify.ts +++ b/back/services/notify.ts @@ -29,6 +29,7 @@ export default class NotificationService { ['pushPlus', this.pushPlus], ['email', this.email], ['webhook', this.webhook], + ['lark', this.lark], ]); private title = ''; @@ -37,9 +38,9 @@ export default class NotificationService { private gotOption = { timeout: 30000, retry: 1, - } + }; - constructor(@Inject('logger') private logger: winston.Logger) { } + constructor(@Inject('logger') private logger: winston.Logger) {} public async notify( title: string, @@ -180,8 +181,9 @@ export default class NotificationService { telegramBotUserId, } = this.params; const authStr = telegramBotProxyAuth ? `${telegramBotProxyAuth}@` : ''; - const url = `https://${telegramBotApiHost ? telegramBotApiHost : 'api.telegram.org' - }/bot${telegramBotToken}/sendMessage`; + const url = `https://${ + telegramBotApiHost ? telegramBotApiHost : 'api.telegram.org' + }/bot${telegramBotToken}/sendMessage`; let agent; if (telegramBotProxyHost && telegramBotProxyPort) { const options: any = { @@ -324,30 +326,30 @@ export default class NotificationService { private async aibotk() { const { aibotkKey, aibotkType, aibotkName } = this.params; - let url = '' - let json = {} + let url = ''; + let json = {}; switch (aibotkType) { case 'room': - url = 'https://api-bot.aibotk.com/openapi/v1/chat/room' + url = 'https://api-bot.aibotk.com/openapi/v1/chat/room'; json = { apiKey: `${aibotkKey}`, roomName: `${aibotkName}`, message: { type: 1, - content: `【青龙快讯】\n\n${this.title}\n${this.content}` - } - } + content: `【青龙快讯】\n\n${this.title}\n${this.content}`, + }, + }; break; case 'contact': - url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact' + url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact'; json = { apiKey: `${aibotkKey}`, name: `${aibotkName}`, message: { type: 1, - content: `【青龙快讯】\n\n${this.title}\n${this.content}` - } - } + content: `【青龙快讯】\n\n${this.title}\n${this.content}`, + }, + }; break; } @@ -355,10 +357,11 @@ export default class NotificationService { .post(url, { ...this.gotOption, json: { - ...json - } - }).json(); - + ...json, + }, + }) + .json(); + return res.code === 0; } @@ -394,6 +397,21 @@ export default class NotificationService { 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() { const { emailPass, emailService, emailUser } = this.params; const transporter = nodemailer.createTransport({ @@ -417,11 +435,19 @@ export default class NotificationService { } private async webhook() { - const { webhookUrl, webhookBody, webhookHeaders, webhookMethod, webhookContentType } = - this.params; + const { + webhookUrl, + webhookBody, + webhookHeaders, + webhookMethod, + webhookContentType, + } = this.params; - const { formatBody, formatUrl } = this.formatNotifyContent(webhookUrl, webhookBody); - if (!formatUrl && !formatBody) { + const { formatBody, formatUrl } = this.formatNotifyContent( + webhookUrl, + webhookBody, + ); + if (!formatUrl && !formatBody) { return false; } const headers = parseHeaders(webhookHeaders); @@ -432,8 +458,8 @@ export default class NotificationService { headers, ...this.gotOption, allowGetBody: true, - ...bodyParam - } + ...bodyParam, + }; const res = await got(formatUrl, options); return String(res.statusCode).startsWith('20'); } @@ -457,8 +483,12 @@ export default class NotificationService { } return { - formatUrl: url.replaceAll('$title', encodeURIComponent(this.title)).replaceAll('$content', encodeURIComponent(this.content)), - formatBody: body.replaceAll('$title', this.title).replaceAll('$content', this.content), - } + formatUrl: url + .replaceAll('$title', encodeURIComponent(this.title)) + .replaceAll('$content', encodeURIComponent(this.content)), + formatBody: body + .replaceAll('$title', this.title) + .replaceAll('$content', this.content), + }; } } diff --git a/sample/notify.js b/sample/notify.js index 9e67b89a..07b93969 100644 --- a/sample/notify.js +++ b/sample/notify.js @@ -110,7 +110,6 @@ let PUSH_PLUS_USER = ''; let QQ_SKEY = ''; let QQ_MODE = ''; - // =======================================智能微秘书设置区域======================================= //官方文档:http://wechat.aibotk.com/docs/about //AIBOTK_KEY: 填写智能微秘书个人中心的apikey @@ -120,6 +119,11 @@ let AIBOTK_KEY = ''; let AIBOTK_TYPE = ''; let AIBOTK_NAME = ''; +// =======================================飞书机器人设置区域======================================= +//官方文档:https://www.feishu.cn/hc/zh-CN/articles/360024984973 +//FSKEY 飞书机器人的 FSKEY +let FSKEY = ''; + //==========================云端环境变量的判断与接收========================= if (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) { 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) { - AIBOTK_TYPE = process.env.AIBOTK_TYPE +if (process.env.AIBOTK_TYPE) { + AIBOTK_TYPE = process.env.AIBOTK_TYPE; } -if(process.env.AIBOTK_NAME) { - AIBOTK_NAME = process.env.AIBOTK_NAME +if (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 PushDeerNotify(text, desp), //PushDeer 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) => { if (GOBOT_URL) { const options = { @@ -326,38 +336,34 @@ function gobotNotify(text, desp, time = 2100) { }, timeout, }; - setTimeout(() => { - $.post(options, (err, resp, data) => { - try { - if (err) { - console.log('发送go-cqhttp通知调用API失败!!\n'); - console.log(err); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('发送go-cqhttp通知调用API失败!!\n'); + console.log(err); + } else { + data = JSON.parse(data); + if (data.retcode === 0) { + console.log('go-cqhttp发送通知消息成功🎉\n'); + } else if (data.retcode === 100) { + console.log(`go-cqhttp发送通知消息异常: ${data.errmsg}\n`); } else { - data = JSON.parse(data); - if (data.retcode === 0) { - console.log('go-cqhttp发送通知消息成功🎉\n'); - } else if (data.retcode === 100) { - console.log(`go-cqhttp发送通知消息异常: ${data.errmsg}\n`); - } else { - console.log( - `go-cqhttp发送通知消息异常\n${JSON.stringify(data)}`, - ); - } + console.log(`go-cqhttp发送通知消息异常\n${JSON.stringify(data)}`); } - } catch (e) { - $.logErr(e, resp); - } finally { - resolve(data); } - }); - }, time); + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); } else { resolve(); } }); } -function serverNotify(text, desp, time = 2100) { +function serverNotify(text, desp) { return new Promise((resolve) => { if (SCKEY) { //微信server酱推送通知一个\n不会换行,需要两个\n才能换行,故做此替换 @@ -372,33 +378,29 @@ function serverNotify(text, desp, time = 2100) { }, timeout, }; - setTimeout(() => { - $.post(options, (err, resp, data) => { - try { - if (err) { - console.log('发送通知调用API失败!!\n'); - console.log(err); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('发送通知调用API失败!!\n'); + console.log(err); + } else { + data = JSON.parse(data); + //server酱和Server酱·Turbo版的返回json格式不太一样 + if (data.errno === 0 || data.data.errno === 0) { + console.log('server酱发送通知消息成功🎉\n'); + } else if (data.errno === 1024) { + // 一分钟内发送相同的内容会触发 + console.log(`server酱发送通知消息异常: ${data.errmsg}\n`); } else { - data = JSON.parse(data); - //server酱和Server酱·Turbo版的返回json格式不太一样 - if (data.errno === 0 || data.data.errno === 0) { - console.log('server酱发送通知消息成功🎉\n'); - } else if (data.errno === 1024) { - // 一分钟内发送相同的内容会触发 - console.log(`server酱发送通知消息异常: ${data.errmsg}\n`); - } else { - console.log( - `server酱发送通知消息异常\n${JSON.stringify(data)}`, - ); - } + console.log(`server酱发送通知消息异常\n${JSON.stringify(data)}`); } - } catch (e) { - $.logErr(e, resp); - } finally { - resolve(data); } - }); - }, time); + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); } else { resolve(); } @@ -418,35 +420,29 @@ function PushDeerNotify(text, desp) { }, timeout, }; - $.post( - options, - (err, resp, data) => { - try { - if (err) { - console.log('发送通知调用API失败!!\n'); - console.log(err); + $.post(options, (err, resp, data) => { + try { + if (err) { + console.log('发送通知调用API失败!!\n'); + console.log(err); + } else { + data = JSON.parse(data); + // 通过返回的result的长度来判断是否成功 + if ( + data.content.result.length !== undefined && + data.content.result.length > 0 + ) { + console.log('PushDeer发送通知消息成功🎉\n'); } else { - data = JSON.parse(data); - // 通过返回的result的长度来判断是否成功 - if ( - data.content.result.length !== undefined && - data.content.result.length > 0 - ) { - console.log('PushDeer发送通知消息成功🎉\n'); - } else { - console.log( - `PushDeer发送通知消息异常\n${JSON.stringify(data)}`, - ); - } + console.log(`PushDeer发送通知消息异常\n${JSON.stringify(data)}`); } - } catch (e) { - $.logErr(e, resp); - } finally { - resolve(data); } - }, - time, - ); + } catch (e) { + $.logErr(e, resp); + } finally { + resolve(data); + } + }); } else { 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 = {}) { return new Promise((resolve) => { if (BARK_PUSH) { @@ -669,7 +588,7 @@ function ddBotNotify(text, desp) { json: { msgtype: 'text', text: { - content: ` ${text}\n\n${desp}`, + content: `${text}\n\n${desp}`, }, }, headers: { @@ -736,7 +655,7 @@ function qywxBotNotify(text, desp) { json: { msgtype: 'text', text: { - content: ` ${text}\n\n${desp}`, + content: `${text}\n\n${desp}`, }, }, headers: { @@ -1005,31 +924,31 @@ function pushPlusNotify(text, desp) { function aibotkNotify(text, desp) { return new Promise((resolve) => { - if(AIBOTK_KEY&&AIBOTK_TYPE&&AIBOTK_NAME) { + if (AIBOTK_KEY && AIBOTK_TYPE && AIBOTK_NAME) { let json = {}; let url = ''; switch (AIBOTK_TYPE) { case 'room': - url = 'https://api-bot.aibotk.com/openapi/v1/chat/room' + url = 'https://api-bot.aibotk.com/openapi/v1/chat/room'; json = { apiKey: `${AIBOTK_KEY}`, roomName: `${AIBOTK_NAME}`, message: { type: 1, - content: `【青龙快讯】\n\n${text}\n${desp}` - } - } + content: `【青龙快讯】\n\n${text}\n${desp}`, + }, + }; break; case 'contact': - url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact' + url = 'https://api-bot.aibotk.com/openapi/v1/chat/contact'; json = { apiKey: `${AIBOTK_KEY}`, name: `${AIBOTK_NAME}`, message: { type: 1, - content: `【青龙快讯】\n\n${text}\n${desp}` - } - } + content: `【青龙快讯】\n\n${text}\n${desp}`, + }, + }; break; } 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 = { diff --git a/sample/notify.py b/sample/notify.py index 70a8ffa5..a12e985b 100644 --- a/sample/notify.py +++ b/sample/notify.py @@ -82,9 +82,9 @@ push_config = { 'TG_PROXY_HOST': '', # tg 机器人的 TG_PROXY_HOST 'TG_PROXY_PORT': '', # tg 机器人的 TG_PROXY_PORT - 'AIBOTK_KEY': '', # 智能微秘书 个人中心的apikey 文档地址:http://wechat.aibotk.com/docs/about - 'AIBOTK_TYPE': '', # 智能微秘书 发送目标 room 或 contact - 'AIBOTK_NAME': '', # 智能微秘书 发送群名 或者好友昵称和type要对应好 + 'AIBOTK_KEY': '', # 智能微秘书 个人中心的apikey 文档地址:http://wechat.aibotk.com/docs/about + 'AIBOTK_TYPE': '', # 智能微秘书 发送目标 room 或 contact + 'AIBOTK_NAME': '', # 智能微秘书 发送群名 或者好友昵称和type要对应好 } notify_function = [] # fmt: on diff --git a/src/utils/config.ts b/src/utils/config.ts index f6b145e0..98107adf 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -93,6 +93,7 @@ export default { { value: 'pushPlus', label: 'PushPlus' }, { value: 'chat', label: '群辉chat' }, { value: 'email', label: '邮箱' }, + { value: 'lark', label: '飞书机器人' }, { value: 'webhook', label: '自定义通知' }, { value: 'closed', label: '已关闭' }, ], @@ -208,7 +209,10 @@ export default { tip: '发送的目标,群组或者好友', required: true, placeholder: '请输入要发送的目标', - items: [{ value: 'room', label: '群聊' }, { value: 'contact', label: '好友' }], + items: [ + { value: 'room', label: '群聊' }, + { value: 'contact', label: '好友' }, + ], }, { label: 'aibotkName', @@ -234,6 +238,13 @@ export default { tip: '一对多推送的“群组编码”(一对多推送下面->您的群组(如无则新建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)', }, ], + lark: [ + { + label: 'larkKey', + tip: '飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973', + required: true, + }, + ], email: [ { label: 'emailService', @@ -254,7 +265,11 @@ export default { label: 'webhookContentType', tip: '请求头Content-Type', 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',