chore: format

This commit is contained in:
xiaojunnuo
2026-05-31 01:41:33 +08:00
parent acd440106b
commit 4b57a0d729
557 changed files with 12530 additions and 14039 deletions
@@ -1,52 +1,52 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'anpush',
title: 'AnPush',
desc: 'https://anpush.com',
name: "anpush",
title: "AnPush",
desc: "https://anpush.com",
needPlus: true,
})
export class AnPushNotification extends BaseNotification {
@NotificationInput({
title: 'API密钥',
title: "API密钥",
component: {
placeholder: '',
placeholder: "",
},
helper: '[获取API密钥](https://anpush.com/push/tool) ',
helper: "[获取API密钥](https://anpush.com/push/tool) ",
required: true,
})
token = '';
token = "";
@NotificationInput({
title: '通道ID',
title: "通道ID",
component: {
placeholder: '',
placeholder: "",
},
helper: '[获取通道ID](https://anpush.com/push/setting)创建通道,复制通道id,填入此处',
helper: "[获取通道ID](https://anpush.com/push/setting)创建通道,复制通道id,填入此处",
required: true,
})
channel = '';
channel = "";
async send(body: NotificationBody) {
if (!this.token) {
throw new Error('token不能为空');
throw new Error("token不能为空");
}
const config = {
url: `https://api.anpush.com/push/${this.token}`,
method: 'POST',
method: "POST",
timeout: 0,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
"Content-Type": "application/x-www-form-urlencoded",
},
data: {
title: body.title,
content: body.content + '\n\n[查看详情](' + body.url + ')',
content: body.content + "\n\n[查看详情](" + body.url + ")",
channel: this.channel,
},
};
const res = await this.http.request(config);
if (res.code != 200) {
throw new Error('发送失败:' + res.msg);
throw new Error("发送失败:" + res.msg);
}
}
}
@@ -13,31 +13,31 @@
* }'
*/
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'bark',
title: 'Bark 通知',
desc: 'Bark 推送通知插件',
name: "bark",
title: "Bark 通知",
desc: "Bark 推送通知插件",
needPlus: true,
})
export class BarkNotification extends BaseNotification {
@NotificationInput({
title: '服务地址',
title: "服务地址",
component: {
placeholder: 'https://api.day.app/your_key',
placeholder: "https://api.day.app/your_key",
},
required: true,
helper: '你的bark服务地址+key',
helper: "你的bark服务地址+key",
})
webhook = '';
webhook = "";
@NotificationInput({
title: '忽略证书校验',
title: "忽略证书校验",
value: false,
component: {
name: 'a-switch',
vModel: 'checked',
name: "a-switch",
vModel: "checked",
},
required: false,
})
@@ -45,7 +45,7 @@ export class BarkNotification extends BaseNotification {
async send(body: NotificationBody) {
if (!this.webhook) {
throw new Error('服务器地址不能为空');
throw new Error("服务器地址不能为空");
}
const payload = {
@@ -55,9 +55,9 @@ export class BarkNotification extends BaseNotification {
await this.http.request({
url: `${this.webhook}`,
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json; charset=utf-8',
"Content-Type": "application/json; charset=utf-8",
},
data: payload,
skipSslVerify: this.skipSslVerify,
@@ -1,79 +1,76 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'dingtalk',
title: '钉钉通知',
desc: '钉钉群聊通知',
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地址',
title: "webhook地址",
component: {
placeholder: 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxx',
placeholder: "https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxxxxxxxxx",
},
helper: '钉钉APP->群聊->设置->机器人->添加机器人->自定义->[创建机器人->复制webhook地址](https://open.dingtalk.com/document/robots/custom-robot-access)',
helper: "钉钉APP->群聊->设置->机器人->添加机器人->自定义->[创建机器人->复制webhook地址](https://open.dingtalk.com/document/robots/custom-robot-access)",
required: true,
})
webhook = '';
webhook = "";
@NotificationInput({
title: '加签密钥',
title: "加签密钥",
component: {
placeholder: 'SECxxxxxxxxxxxxxxxxxxxxx',
placeholder: "SECxxxxxxxxxxxxxxxxxxxxx",
},
helper: '必须选择一种安全设置,请选择加密密钥',
helper: "必须选择一种安全设置,请选择加密密钥",
required: false,
})
secret = '';
secret = "";
@NotificationInput({
title: '@用户ID',
title: "@用户ID",
component: {
placeholder: '非必填,填写完一个按回车',
name: 'a-select',
vModel: 'value',
mode: 'tags',
placeholder: "非必填,填写完一个按回车",
name: "a-select",
vModel: "value",
mode: "tags",
multiple: true,
open: false,
},
helper: '填写要@的用户ID',
helper: "填写要@的用户ID",
required: false,
})
atUserIds:string[];
atUserIds: string[];
@NotificationInput({
title: '@用户手机号',
title: "@用户手机号",
component: {
placeholder: '非必填,填写一个按回车',
name: 'a-select',
vModel: 'value',
mode: 'tags',
placeholder: "非必填,填写一个按回车",
name: "a-select",
vModel: "value",
mode: "tags",
multiple: true,
open: false,
},
helper: '填写要@的用户的手机号',
helper: "填写要@的用户的手机号",
required: false,
})
atMobiles:string[];
atMobiles: string[];
@NotificationInput({
title: '@all',
title: "@all",
component: {
placeholder: '非必填',
name: 'a-switch',
vModel:"checked"
placeholder: "非必填",
name: "a-switch",
vModel: "checked",
},
helper: '是否@所有人',
helper: "是否@所有人",
required: false,
})
isAtAll:boolean;
isAtAll: boolean;
async sign(){
async sign() {
const timestamp = Date.now();
const secret = this.secret;
const stringToSign = `${timestamp}\n${secret}`;
@@ -83,21 +80,20 @@ export class DingTalkNotification extends BaseNotification {
* 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);
const crypto = await import("crypto");
const hmac = crypto.createHmac("sha256", secret);
hmac.update(stringToSign);
const sign = encodeURIComponent(Buffer.from(hmac.digest()).toString('base64'));
const sign = encodeURIComponent(Buffer.from(hmac.digest()).toString("base64"));
return {
timestamp,
sign,
};
}
async send(body: NotificationBody) {
if (!this.webhook) {
throw new Error('webhook地址不能为空');
throw new Error("webhook地址不能为空");
}
/**
*
@@ -109,36 +105,36 @@ export class DingTalkNotification extends BaseNotification {
*/
let webhook = this.webhook;
if(this.secret){
if (this.secret) {
const signRet = await this.sign();
webhook = `${webhook}&timestamp=${signRet.timestamp}&sign=${signRet.sign}`;
}
const at :any= {}
if(this.atUserIds && this.atUserIds.length>0){
at.atUserIds = this.atUserIds;
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.atMobiles && this.atMobiles.length > 0) {
at.atMobiles = this.atMobiles;
}
if(this.isAtAll){
at.isAtAll = true;
if (this.isAtAll) {
at.isAtAll = true;
}
const color = body.errorMessage?'red':'green';
const color = body.errorMessage ? "red" : "green";
const res = await this.http.request({
url: webhook,
method: 'POST',
method: "POST",
data: {
at: at,
markdown: {
title: body.title,
text: `<font color='${color}'>${body.title}</font>\n\n\n ${body.content}\n\n\n[查看详情](${body.url})`,
},
msgtype:"markdown"
msgtype: "markdown",
},
});
if(res.errcode>100){
if (res.errcode > 100) {
throw new Error(`发送失败:${res.errmsg}`);
}
}
@@ -1,51 +1,51 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'discord',
title: 'Discord 通知',
desc: 'Discord 机器人通知',
name: "discord",
title: "Discord 通知",
desc: "Discord 机器人通知",
needPlus: true,
})
export class DiscordNotification extends BaseNotification {
@NotificationInput({
title: 'Webhook URL',
title: "Webhook URL",
component: {
placeholder: 'https://discord.com/api/webhooks/xxxxx/xxxx',
placeholder: "https://discord.com/api/webhooks/xxxxx/xxxx",
},
helper: '[Discord Webhook 说明](https://discord.com/developers/docs/resources/webhook#execute-webhook)',
helper: "[Discord Webhook 说明](https://discord.com/developers/docs/resources/webhook#execute-webhook)",
required: true,
})
webhook = '';
webhook = "";
@NotificationInput({
title: '提醒指定成员',
title: "提醒指定成员",
component: {
name: 'a-select',
vModel: 'value',
mode: 'tags',
name: "a-select",
vModel: "value",
mode: "tags",
open: false,
},
required: false,
helper: '填写成员的Id,或者角色Id&id),或者everyone',
helper: "填写成员的Id,或者角色Id&id),或者everyone",
})
mentionedList!: string[];
@NotificationInput({
title: '代理',
title: "代理",
component: {
placeholder: 'http://xxxxx:xx',
placeholder: "http://xxxxx:xx",
},
helper: '使用https_proxy',
helper: "使用https_proxy",
required: false,
})
httpsProxy = '';
httpsProxy = "";
@NotificationInput({
title: '忽略证书校验',
title: "忽略证书校验",
value: false,
component: {
name: 'a-switch',
vModel: 'checked',
name: "a-switch",
vModel: "checked",
},
required: false,
})
@@ -53,13 +53,13 @@ export class DiscordNotification extends BaseNotification {
async send(body: NotificationBody) {
if (!this.webhook) {
throw new Error('Webhook URL 不能为空');
throw new Error("Webhook URL 不能为空");
}
// 创建 Discord 消息体
let content = `${body.title}\n${body.content}\n\n[查看详情](${body.url})`;
if (this.mentionedList && this.mentionedList.length > 0) {
content += `\n${this.mentionedList.map(item => `<@${item}> `).join('')}`;
content += `\n${this.mentionedList.map(item => `<@${item}> `).join("")}`;
}
const json = {
@@ -68,7 +68,7 @@ export class DiscordNotification extends BaseNotification {
await this.http.request({
url: this.webhook,
method: 'POST',
method: "POST",
data: json,
httpProxy: this.httpsProxy,
skipSslVerify: this.skipSslVerify,
@@ -1,41 +1,40 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'email',
title: '电子邮件',
desc: '电子邮件通知',
name: "email",
title: "电子邮件",
desc: "电子邮件通知",
order: -100,
})
export class EmailNotification extends BaseNotification {
@NotificationInput({
title: '收件人邮箱',
title: "收件人邮箱",
component: {
name: 'email-selector',
vModel: 'value',
mode: 'tags',
name: "email-selector",
vModel: "value",
mode: "tags",
// open: false,
},
required: true,
helper: '可以填写多个,填写一个按回车键再填写下一个\n需要先[配置邮件服务器](#/sys/settings/email)',
helper: "可以填写多个,填写一个按回车键再填写下一个\n需要先[配置邮件服务器](#/sys/settings/email)",
})
receivers!: string[];
async send(body: NotificationBody) {
const templateData = {
...body,
}
const emailSend:any = {
};
const emailSend: any = {
receivers: this.receivers,
}
};
if (body.attachments && body.attachments.length > 0) {
emailSend.attachments = body.attachments;
}
await this.ctx.emailService.sendByTemplate({
type: body.notificationType,
data: templateData,
...emailSend
})
...emailSend,
});
// await this.ctx.emailService.send({
// subject: body.title,
@@ -1,76 +1,73 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'feishu',
title: '飞书通知',
desc: '飞书群聊webhook通知',
name: "feishu",
title: "飞书通知",
desc: "飞书群聊webhook通知",
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 FeishuNotification extends BaseNotification {
@NotificationInput({
title: 'webhook地址',
title: "webhook地址",
component: {
placeholder: 'https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxx',
placeholder: "https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxxxxxxxxxx",
},
helper: '飞书APP->群聊->设置->机器人->添加机器人->自定义webhook->[创建机器人->复制webhook地址](https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot?lang=zh-CN)',
helper: "飞书APP->群聊->设置->机器人->添加机器人->自定义webhook->[创建机器人->复制webhook地址](https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot?lang=zh-CN)",
required: true,
})
webhook = '';
webhook = "";
@NotificationInput({
title: '加签密钥',
title: "加签密钥",
component: {
placeholder: 'SECxxxxxxxxxxxxxxxxxxxxx',
placeholder: "SECxxxxxxxxxxxxxxxxxxxxx",
},
helper: '必须选择一种安全设置,建议选择加密密钥',
helper: "必须选择一种安全设置,建议选择加密密钥",
required: false,
})
secret = '';
secret = "";
@NotificationInput({
title: '@用户',
title: "@用户",
component: {
placeholder: '非必填,支持多个,填写完一个按回车',
name: 'a-select',
vModel: 'value',
mode: 'tags',
placeholder: "非必填,支持多个,填写完一个按回车",
name: "a-select",
vModel: "value",
mode: "tags",
multiple: true,
open: false,
},
helper: '填写要@的用户ID:【ou_xxxxxxxxx】\n用户ID获取方法,[查看OpenId获取方法](https://open.feishu.cn/document/home/user-identity-introduction/open-id)',
helper: "填写要@的用户ID:【ou_xxxxxxxxx】\n用户ID获取方法,[查看OpenId获取方法](https://open.feishu.cn/document/home/user-identity-introduction/open-id)",
required: false,
})
atUserIds:string[];
atUserIds: string[];
@NotificationInput({
title: '@all',
title: "@all",
component: {
placeholder: '非必填',
name: 'a-switch',
vModel:"checked"
placeholder: "非必填",
name: "a-switch",
vModel: "checked",
},
helper: '是否@所有人',
helper: "是否@所有人",
required: false,
})
isAtAll:boolean;
isAtAll: boolean;
async sign(){
const crypto = await import('crypto');
async sign() {
const crypto = await import("crypto");
const secret = this.secret;
const timestamp = Math.floor(Date.now() / 1000);
const str = Buffer.from(`${timestamp}\n${secret}`, 'utf8');
const sign = crypto.createHmac('SHA256', str);
const str = Buffer.from(`${timestamp}\n${secret}`, "utf8");
const sign = crypto.createHmac("SHA256", str);
sign.update(Buffer.alloc(0));
return { timestamp, sign: sign.digest('base64') };
return { timestamp, sign: sign.digest("base64") };
}
async send(body: NotificationBody) {
if (!this.webhook) {
throw new Error('webhook地址不能为空');
throw new Error("webhook地址不能为空");
}
/**
*
@@ -81,8 +78,7 @@ export class FeishuNotification extends BaseNotification {
* }
*/
let webhook = this.webhook;
const webhook = this.webhook;
/*
// @ 单个用户
@@ -90,109 +86,109 @@ export class FeishuNotification extends BaseNotification {
// @ 所有人
<at user_id="all">所有人</at>
*/
let atText = ""
if(this.atUserIds && this.atUserIds.length>0){
atText = this.atUserIds.map((id:string)=>{
const nameIndex = id.indexOf(".");
let name = id
if(nameIndex>0){
name = id.substring(nameIndex+1)
}
return `<at id=${id}>${name}</at>`
}).join("");
let atText = "";
if (this.atUserIds && this.atUserIds.length > 0) {
atText = this.atUserIds
.map((id: string) => {
const nameIndex = id.indexOf(".");
let name = id;
if (nameIndex > 0) {
name = id.substring(nameIndex + 1);
}
return `<at id=${id}>${name}</at>`;
})
.join("");
}
if(this.isAtAll){
atText = `<at id=all>所有人</at>`
if (this.isAtAll) {
atText = `<at id=all>所有人</at>`;
}
if (atText){
atText = `\n${atText}`
if (atText) {
atText = `\n${atText}`;
}
let sign:any = {}
if(this.secret){
let sign: any = {};
if (this.secret) {
const signRet = await this.sign();
sign = {
timestamp: signRet.timestamp,
sign: signRet.sign
}
sign: signRet.sign,
};
}
const cardBody = {
"msg_type": "interactive",
"card": {
"schema": "2.0",
"config": {
"update_multi": true,
"style": {
"text_size": {
"normal_v2": {
"default": "normal",
"pc": "normal",
"mobile": "heading"
}
}
}
},
"header": {
"title": {
"tag": "plain_text",
"content": body.title
msg_type: "interactive",
card: {
schema: "2.0",
config: {
update_multi: true,
style: {
text_size: {
normal_v2: {
default: "normal",
pc: "normal",
mobile: "heading",
},
},
},
"subtitle": {
"tag": "plain_text",
"content": ""
},
"template": body.errorMessage?"red":"green",
"padding": "12px 12px 12px 12px"
},
"body": {
"direction": "vertical",
"padding": "12px 12px 12px 12px",
"elements": [
header: {
title: {
tag: "plain_text",
content: body.title,
},
subtitle: {
tag: "plain_text",
content: "",
},
template: body.errorMessage ? "red" : "green",
padding: "12px 12px 12px 12px",
},
body: {
direction: "vertical",
padding: "12px 12px 12px 12px",
elements: [
{
"tag": "markdown",
"content": body.content+atText,
"text_align": "left",
"text_size": "normal_v2",
"margin": "0px 0px 0px 0px"
tag: "markdown",
content: body.content + atText,
text_align: "left",
text_size: "normal_v2",
margin: "0px 0px 0px 0px",
},
{
"tag": "button",
"text": {
"tag": "plain_text",
"content": "查看详情"
tag: "button",
text: {
tag: "plain_text",
content: "查看详情",
},
"type": "default",
"width": "default",
"size": "medium",
"behaviors": [
type: "default",
width: "default",
size: "medium",
behaviors: [
{
"type": "open_url",
"default_url": body.url,
"pc_url": "",
"ios_url": "",
"android_url": ""
}
type: "open_url",
default_url: body.url,
pc_url: "",
ios_url: "",
android_url: "",
},
],
"margin": "0px 0px 0px 0px"
}
]
margin: "0px 0px 0px 0px",
},
],
},
}
}
},
};
const res = await this.http.request({
url: webhook,
method: 'POST',
method: "POST",
data: {
...sign,
...cardBody
...cardBody,
},
});
if(res.code>100){
if (res.code > 100) {
throw new Error(`发送失败:${res.msg}`);
}
}
@@ -1,16 +1,16 @@
export * from './qywx/index.js';
export * from './email/index.js';
export * from './iyuu/index.js';
export * from './webhook/index.js';
export * from './serverchan/index.js';
export * from './serverchan3/index.js';
export * from './anpush/index.js';
export * from './telegram/index.js';
export * from './discord/index.js';
export * from './slack/index.js';
export * from './bark/index.js';
export * from './feishu/index.js';
export * from './dingtalk/index.js';
export * from './vocechat/index.js';
export * from './onebot/index.js';
export * from './meow/index.js';
export * from "./qywx/index.js";
export * from "./email/index.js";
export * from "./iyuu/index.js";
export * from "./webhook/index.js";
export * from "./serverchan/index.js";
export * from "./serverchan3/index.js";
export * from "./anpush/index.js";
export * from "./telegram/index.js";
export * from "./discord/index.js";
export * from "./slack/index.js";
export * from "./bark/index.js";
export * from "./feishu/index.js";
export * from "./dingtalk/index.js";
export * from "./vocechat/index.js";
export * from "./onebot/index.js";
export * from "./meow/index.js";
@@ -1,32 +1,32 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'iyuu',
title: '爱语飞飞微信通知(iyuu)',
desc: 'https://iyuu.cn/',
name: "iyuu",
title: "爱语飞飞微信通知(iyuu)",
desc: "https://iyuu.cn/",
needPlus: true,
})
export class IyuuNotification extends BaseNotification {
@NotificationInput({
title: 'Token令牌',
title: "Token令牌",
component: {
placeholder: '',
placeholder: "",
},
helper: 'https://iyuu.cn/ 微信扫码获取',
helper: "https://iyuu.cn/ 微信扫码获取",
required: true,
})
token = '';
token = "";
async send(body: NotificationBody) {
if (!this.token) {
throw new Error('token不能为空');
throw new Error("token不能为空");
}
const res = await this.http.request({
url: `https://iyuu.cn/${this.token}.send`,
method: 'POST',
method: "POST",
data: {
text: body.title,
desp: body.content + '\n\n[查看详情](' + body.url + ')',
desp: body.content + "\n\n[查看详情](" + body.url + ")",
},
});
@@ -1,4 +1,4 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
/**
* POST请求
@@ -38,43 +38,42 @@ Content-Type: application/json
}
*/
@IsNotification({
name: 'meow',
title: 'MeoW通知',
desc: 'https://api.chuckfang.com/',
name: "meow",
title: "MeoW通知",
desc: "https://api.chuckfang.com/",
needPlus: false,
})
export class MeowNotification extends BaseNotification {
@NotificationInput({
title: 'MeoW接口地址',
title: "MeoW接口地址",
component: {
placeholder: 'https://api.xxxxxx.com',
placeholder: "https://api.xxxxxx.com",
},
required: true,
})
endpoint = '';
endpoint = "";
@NotificationInput({
title: '昵称',
title: "昵称",
component: {
placeholder: '',
placeholder: "",
},
required: true,
})
nickName = '';
nickName = "";
async send(body: NotificationBody) {
if (!this.nickName) {
throw new Error('昵称不能为空');
throw new Error("昵称不能为空");
}
let endpoint = this.endpoint;
if (!endpoint.endsWith('/')) {
endpoint += '/';
if (!endpoint.endsWith("/")) {
endpoint += "/";
}
const url = `${endpoint}${this.nickName}/`;
const res = await this.http.request({
url: url,
method: 'POST',
method: "POST",
data: {
text: body.title,
msg: body.content,
@@ -1,135 +1,131 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
import axios from "axios";
/**
* 文档: https://github.com/botuniverse/onebot-11
* 教程: https://ayakasuki.com/
*/
@IsNotification({
name: 'onebot',
title: 'OneBot V11 通知',
desc: '通过动态拼接URL发送 OneBot V11 协议消息',
needPlus: false,
})
export class OneBotNotification extends BaseNotification {
// 基础服务地址(不含路径)
@NotificationInput({
title: '服务地址',
component: {
placeholder: 'http://xxxx.xxxx.xxxx',
},
helper: 'OneBot 服务的基础地址(不包含action路径)',
required: true,
rules: [
{
type: 'url',
message: '请输入有效的HTTP/HTTPS地址'
}
]
})
baseUrl = '';
// 目标类型选择
@NotificationInput({
title: '目标类型',
component: {
name: 'a-select',
options: [
{ value: 'group', label: '群聊' },
{ value: 'private', label: '私聊' },
],
},
required: true,
helper: '选择消息发送的目标类型',
})
targetType = 'group';
// 目标ID配置
@NotificationInput({
title: '目标ID',
component: {
name: 'a-input-number',
placeholder: '123456789',
},
helper: '群聊ID或用户ID(纯数字)',
required: true,
})
targetId = '';
// 鉴权密钥(非必填)
@NotificationInput({
title: '鉴权密钥',
component: {
placeholder: 'xxxxxxxxxx',
},
helper: '(选填)访问API的授权令牌(无token时留空)',
required: false, // 关键修改点
})
accessToken = '';
// 构建完整请求URL(支持无token场景)
private buildFullUrl(): string {
const action = this.targetType === 'group'
? 'send_group_msg'
: 'send_private_msg';
let url = `${this.baseUrl}/${action}`;
// 动态添加access_token参数(仅当存在时)
if (this.accessToken) {
url += `?access_token=${encodeURIComponent(this.accessToken)}`;
}
return url;
}
// 构建消息内容
private buildMessage(body: NotificationBody): string {
return body.title
? `${body.title}\n${body.content}`
: body.content;
}
// 构建请求体(动态字段)
private buildRequestBody(body: NotificationBody): object {
return {
[this.targetType === 'group' ? 'group_id' : 'user_id']: Number(this.targetId),
message: this.buildMessage(body),
auto_escape: false
};
}
// 发送通知主逻辑
async send(body: NotificationBody) {
const fullUrl = this.buildFullUrl();
const requestBody = this.buildRequestBody(body);
try {
console.debug("[ONEBOT] 最终请求URL:", fullUrl);
console.debug("[ONEBOT] 请求体:", JSON.stringify(requestBody));
console.debug("[ONEBOT] 使用Token:", !!this.accessToken); // 明确token使用状态
const response = await axios.post(fullUrl, requestBody, {
timeout: 5000,
headers: {
'Content-Type': 'application/json',
'User-Agent': 'Certd-Notification/1.0'
}
});
// 响应验证(保持不变)
if (response.data?.retcode !== 0) {
throw new Error(`[${response.data.retcode}] ${response.data.message}`);
}
return response.data;
} catch (error) {
console.error('[ONEBOT] 请求失败:', {
url: fullUrl,
tokenUsed: !!this.accessToken, // 记录token使用状态
error: error.response?.data || error.message
});
throw new Error(`OneBot通知发送失败: ${error.message}`);
}
}
}
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
import axios from "axios";
/**
* 文档: https://github.com/botuniverse/onebot-11
* 教程: https://ayakasuki.com/
*/
@IsNotification({
name: "onebot",
title: "OneBot V11 通知",
desc: "通过动态拼接URL发送 OneBot V11 协议消息",
needPlus: false,
})
export class OneBotNotification extends BaseNotification {
// 基础服务地址(不含路径)
@NotificationInput({
title: "服务地址",
component: {
placeholder: "http://xxxx.xxxx.xxxx",
},
helper: "OneBot 服务的基础地址(不包含action路径)",
required: true,
rules: [
{
type: "url",
message: "请输入有效的HTTP/HTTPS地址",
},
],
})
baseUrl = "";
// 目标类型选择
@NotificationInput({
title: "目标类型",
component: {
name: "a-select",
options: [
{ value: "group", label: "群聊" },
{ value: "private", label: "私聊" },
],
},
required: true,
helper: "选择消息发送的目标类型",
})
targetType = "group";
// 目标ID配置
@NotificationInput({
title: "目标ID",
component: {
name: "a-input-number",
placeholder: "123456789",
},
helper: "群聊ID或用户ID(纯数字)",
required: true,
})
targetId = "";
// 鉴权密钥(非必填)
@NotificationInput({
title: "鉴权密钥",
component: {
placeholder: "xxxxxxxxxx",
},
helper: "(选填)访问API的授权令牌(无token时留空)",
required: false, // 关键修改点
})
accessToken = "";
// 构建完整请求URL(支持无token场景)
private buildFullUrl(): string {
const action = this.targetType === "group" ? "send_group_msg" : "send_private_msg";
let url = `${this.baseUrl}/${action}`;
// 动态添加access_token参数(仅当存在时)
if (this.accessToken) {
url += `?access_token=${encodeURIComponent(this.accessToken)}`;
}
return url;
}
// 构建消息内容
private buildMessage(body: NotificationBody): string {
return body.title ? `${body.title}\n${body.content}` : body.content;
}
// 构建请求体(动态字段)
private buildRequestBody(body: NotificationBody): object {
return {
[this.targetType === "group" ? "group_id" : "user_id"]: Number(this.targetId),
message: this.buildMessage(body),
auto_escape: false,
};
}
// 发送通知主逻辑
async send(body: NotificationBody) {
const fullUrl = this.buildFullUrl();
const requestBody = this.buildRequestBody(body);
try {
console.debug("[ONEBOT] 最终请求URL:", fullUrl);
console.debug("[ONEBOT] 请求体:", JSON.stringify(requestBody));
console.debug("[ONEBOT] 使用Token:", !!this.accessToken); // 明确token使用状态
const response = await axios.post(fullUrl, requestBody, {
timeout: 5000,
headers: {
"Content-Type": "application/json",
"User-Agent": "Certd-Notification/1.0",
},
});
// 响应验证(保持不变)
if (response.data?.retcode !== 0) {
throw new Error(`[${response.data.retcode}] ${response.data.message}`);
}
return response.data;
} catch (error) {
console.error("[ONEBOT] 请求失败:", {
url: fullUrl,
tokenUsed: !!this.accessToken, // 记录token使用状态
error: error.response?.data || error.message,
});
throw new Error(`OneBot通知发送失败: ${error.message}`);
}
}
}
@@ -1,58 +1,58 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'qywx',
title: '企业微信通知',
desc: '企业微信群聊机器人通知',
name: "qywx",
title: "企业微信通知",
desc: "企业微信群聊机器人通知",
needPlus: true,
})
export class QywxNotification extends BaseNotification {
@NotificationInput({
title: 'webhook地址',
title: "webhook地址",
component: {
placeholder: 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxx',
placeholder: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxx",
},
helper: '[企微群聊机器人配置说明](https://developer.work.weixin.qq.com/document/path/91770)',
helper: "[企微群聊机器人配置说明](https://developer.work.weixin.qq.com/document/path/91770)",
required: true,
})
webhook = '';
webhook = "";
@NotificationInput({
title: '提醒指定成员',
title: "提醒指定成员",
component: {
name: 'a-select',
vModel: 'value',
mode: 'tags',
name: "a-select",
vModel: "value",
mode: "tags",
open: false,
},
required: false,
helper: '填写成员名字,@all 为提醒所有人',
helper: "填写成员名字,@all 为提醒所有人",
})
mentionedList!: string[];
@NotificationInput({
title: '提醒指定手机号成员',
title: "提醒指定手机号成员",
component: {
name: 'a-select',
vModel: 'value',
mode: 'tags',
name: "a-select",
vModel: "value",
mode: "tags",
open: false,
},
required: false,
helper: '填写成员手机号,@all 为提醒所有人',
helper: "填写成员手机号,@all 为提醒所有人",
})
mentionedMobileList!: string[];
async send(body: NotificationBody) {
if (!this.webhook) {
throw new Error('webhook地址不能为空');
throw new Error("webhook地址不能为空");
}
await this.http.request({
url: this.webhook,
method: 'POST',
method: "POST",
data: {
msgtype: 'text',
msgtype: "text",
text: {
content: `${body.title}\n${body.content}\n查看详情: ${body.url}`,
mentioned_list: this.mentionedList,
@@ -61,7 +61,6 @@ export class QywxNotification extends BaseNotification {
},
});
//Markdown 模式不支持@
// const color = body.errorMessage?'red':'green';
@@ -1,55 +1,55 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'serverchan',
title: 'Server酱ᵀ',
desc: 'https://sct.ftqq.com/',
name: "serverchan",
title: "Server酱ᵀ",
desc: "https://sct.ftqq.com/",
needPlus: true,
})
export class ServerChanNotification extends BaseNotification {
@NotificationInput({
title: '服务地址',
value: 'https://sctapi.ftqq.com',
title: "服务地址",
value: "https://sctapi.ftqq.com",
required: true,
})
endpoint = 'https://sctapi.ftqq.com';
endpoint = "https://sctapi.ftqq.com";
@NotificationInput({
title: 'SendKey',
title: "SendKey",
component: {
placeholder: 'https://sctapi.ftqq.com/<SENDKEY>.send',
placeholder: "https://sctapi.ftqq.com/<SENDKEY>.send",
},
helper: 'https://sct.ftqq.com/ 微信扫码获取',
helper: "https://sct.ftqq.com/ 微信扫码获取",
required: true,
})
sendKey = '';
sendKey = "";
@NotificationInput({
title: '消息通道号',
title: "消息通道号",
component: {
placeholder: '9|66',
placeholder: "9|66",
},
helper: '可以不填,最多两个通道,[通道配置说明](https://sct.ftqq.com/sendkey)',
helper: "可以不填,最多两个通道,[通道配置说明](https://sct.ftqq.com/sendkey)",
required: false,
})
channel: string;
@NotificationInput({
title: '是否隐藏IP',
title: "是否隐藏IP",
component: {
name: 'a-switch',
vModel: 'checked',
name: "a-switch",
vModel: "checked",
},
required: false,
})
noip: boolean;
@NotificationInput({
title: '忽略证书校验',
title: "忽略证书校验",
value: false,
component: {
name: 'a-switch',
vModel: 'checked',
name: "a-switch",
vModel: "checked",
},
required: false,
})
@@ -57,14 +57,14 @@ export class ServerChanNotification extends BaseNotification {
async send(body: NotificationBody) {
if (!this.sendKey) {
throw new Error('sendKey不能为空');
throw new Error("sendKey不能为空");
}
await this.http.request({
url: `${this.endpoint}/${this.sendKey}.send`,
method: 'POST',
method: "POST",
data: {
text: body.title,
desp: body.content + '\n\n[查看详情](' + body.url + ')',
desp: body.content + "\n\n[查看详情](" + body.url + ")",
},
skipSslVerify: this.skipSslVerify,
});
@@ -1,46 +1,46 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'serverchan3',
title: 'Server酱³',
desc: 'https://doc.sc3.ft07.com/serverchan3',
name: "serverchan3",
title: "Server酱³",
desc: "https://doc.sc3.ft07.com/serverchan3",
needPlus: true,
})
export class ServerChan3Notification extends BaseNotification {
@NotificationInput({
title: 'ApiURL',
title: "ApiURL",
component: {
placeholder: 'https://uid.push.ft07.com/send/sendKey.send',
placeholder: "https://uid.push.ft07.com/send/sendKey.send",
},
required: true,
})
apiURL = '';
apiURL = "";
@NotificationInput({
title: '标签Tags',
title: "标签Tags",
component: {
name: 'a-select',
vModel: 'value',
mode: 'tags',
name: "a-select",
vModel: "value",
mode: "tags",
open: false,
},
helper: '支持多个,回车后填写下一个',
helper: "支持多个,回车后填写下一个",
required: false,
})
tags: string[];
@NotificationInput({
title: 'short',
title: "short",
required: false,
})
short: string;
@NotificationInput({
title: '忽略证书校验',
title: "忽略证书校验",
value: false,
component: {
name: 'a-switch',
vModel: 'checked',
name: "a-switch",
vModel: "checked",
},
required: false,
})
@@ -48,15 +48,15 @@ export class ServerChan3Notification extends BaseNotification {
async send(body: NotificationBody) {
if (!this.apiURL) {
throw new Error('sendKey不能为空');
throw new Error("sendKey不能为空");
}
await this.http.request({
url: `${this.apiURL}`,
method: 'POST',
method: "POST",
data: {
text: body.title,
desp: body.content + '\n\n[查看详情](' + body.url + ')',
tags: this.tags?.join('|') || undefined,
desp: body.content + "\n\n[查看详情](" + body.url + ")",
tags: this.tags?.join("|") || undefined,
short: this.short,
},
skipSslVerify: this.skipSslVerify,
@@ -1,38 +1,38 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'slack',
title: 'Slack通知',
desc: 'Slack消息推送通知',
name: "slack",
title: "Slack通知",
desc: "Slack消息推送通知",
needPlus: true,
})
export class SlackNotification extends BaseNotification {
@NotificationInput({
title: 'webhook地址',
title: "webhook地址",
component: {
placeholder: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX',
placeholder: "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
},
helper: '[APPS](https://api.slack.com/apps/)->进入APP->incoming-webhooks->Add New Webhook to Workspace',
helper: "[APPS](https://api.slack.com/apps/)->进入APP->incoming-webhooks->Add New Webhook to Workspace",
required: true,
})
webhook = '';
webhook = "";
@NotificationInput({
title: '代理',
title: "代理",
component: {
placeholder: 'http://xxxxx:xx',
placeholder: "http://xxxxx:xx",
},
helper: '使用https_proxy',
helper: "使用https_proxy",
required: false,
})
httpsProxy = '';
httpsProxy = "";
@NotificationInput({
title: '忽略证书校验',
title: "忽略证书校验",
value: false,
component: {
name: 'a-switch',
vModel: 'checked',
name: "a-switch",
vModel: "checked",
},
required: false,
})
@@ -40,12 +40,12 @@ export class SlackNotification extends BaseNotification {
async send(body: NotificationBody) {
if (!this.webhook) {
throw new Error('token不能为空');
throw new Error("token不能为空");
}
await this.http.request({
url: this.webhook,
method: 'POST',
method: "POST",
data: {
text: `${body.title}\n${body.content}\n\n[查看详情](${body.url})`,
},
@@ -1,58 +1,58 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'telegram',
title: 'Telegram通知',
desc: 'Telegram Bot推送通知',
name: "telegram",
title: "Telegram通知",
desc: "Telegram Bot推送通知",
needPlus: true,
})
export class TelegramNotification extends BaseNotification {
@NotificationInput({
title: 'URL',
value: 'https://api.telegram.org',
title: "URL",
value: "https://api.telegram.org",
component: {
placeholder: 'https://api.telegram.org',
placeholder: "https://api.telegram.org",
},
required: true,
})
endpoint = 'https://api.telegram.org';
endpoint = "https://api.telegram.org";
@NotificationInput({
title: 'Bot Token',
title: "Bot Token",
component: {
placeholder: '123456789:ABCdefGhijklmnopqrstUVWXyz',
placeholder: "123456789:ABCdefGhijklmnopqrstUVWXyz",
},
helper: '[token获取](https://core.telegram.org/bots/features#botfather)',
helper: "[token获取](https://core.telegram.org/bots/features#botfather)",
required: true,
})
botToken = '';
botToken = "";
@NotificationInput({
title: '聊天ID',
title: "聊天ID",
component: {
placeholder: '聊天ID,例如 123456789 或 @channelusername',
placeholder: "聊天ID,例如 123456789 或 @channelusername",
},
helper: '用户ID(纯数字)或频道名称(@xxxx)',
helper: "用户ID(纯数字)或频道名称(@xxxx)",
required: true,
})
chatId = '';
chatId = "";
@NotificationInput({
title: '代理',
title: "代理",
component: {
placeholder: 'http://xxxxx:xx',
placeholder: "http://xxxxx:xx",
},
helper: '使用https_proxy',
helper: "使用https_proxy",
required: false,
})
httpsProxy = '';
httpsProxy = "";
@NotificationInput({
title: '忽略证书校验',
title: "忽略证书校验",
value: false,
component: {
name: 'a-switch',
vModel: 'checked',
name: "a-switch",
vModel: "checked",
},
required: false,
})
@@ -60,13 +60,13 @@ export class TelegramNotification extends BaseNotification {
replaceText(text: string) {
// .*()<> 等都需要用\\进行替换
return text.replace(/[_*[\]()~`>#\+\-=|{}.!]/g, '\\$&');
return text.replace(/[_*[\]()~`>#\+\-=|{}.!]/g, "\\$&");
// .replace(/([\\_*`|!.[\](){}>+#=~-])/gm, '\\$1')
// return text.replace(/[\\.*()<>]/g, '\\$&');
}
async send(body: NotificationBody) {
if (!this.botToken || !this.chatId) {
throw new Error('Bot Token 和聊天ID不能为空');
throw new Error("Bot Token 和聊天ID不能为空");
}
// 构建消息内容
@@ -78,11 +78,11 @@ export class TelegramNotification extends BaseNotification {
// 发送 HTTP 请求
await this.http.request({
url: url,
method: 'POST',
method: "POST",
data: {
chat_id: this.chatId,
text: messageContent,
parse_mode: 'MarkdownV2', // 或使用 'HTML' 取决于需要的格式
parse_mode: "MarkdownV2", // 或使用 'HTML' 取决于需要的格式
},
httpProxy: this.httpsProxy,
skipSslVerify: this.skipSslVerify,
@@ -1,61 +1,61 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
@IsNotification({
name: 'vocechat',
title: 'VoceChat通知',
desc: 'https://voce.chat',
name: "vocechat",
title: "VoceChat通知",
desc: "https://voce.chat",
needPlus: true,
})
export class VoceChatNotification extends BaseNotification {
@NotificationInput({
title: '服务地址',
title: "服务地址",
component: {
placeholder: 'https://replace.your.domain',
placeholder: "https://replace.your.domain",
},
required: true,
})
endpoint = '';
endpoint = "";
@NotificationInput({
title: 'apiKey',
title: "apiKey",
component: {
placeholder: '',
placeholder: "",
},
helper: '[获取APIKEY](https://doc.voce.chat/bot/bot-and-webhook)',
helper: "[获取APIKEY](https://doc.voce.chat/bot/bot-and-webhook)",
required: true,
})
apiKey = '';
apiKey = "";
@NotificationInput({
title: '目标类型',
title: "目标类型",
component: {
name: 'a-select',
name: "a-select",
options: [
{ value: 'user', label: '用户' },
{ value: 'channel', label: '频道' },
{ value: "user", label: "用户" },
{ value: "channel", label: "频道" },
],
},
required: true,
helper: '发送消息的目标类型',
helper: "发送消息的目标类型",
})
targetType = '';
targetType = "";
@NotificationInput({
title: '目标ID',
title: "目标ID",
component: {
placeholder: '发送消息的目标ID',
placeholder: "发送消息的目标ID",
},
required: true,
helper: '目标ID可以是用户ID或频道ID',
helper: "目标ID可以是用户ID或频道ID",
})
targetId = '';
targetId = "";
@NotificationInput({
title: '忽略证书校验',
title: "忽略证书校验",
value: false,
component: {
name: 'a-switch',
vModel: 'checked',
name: "a-switch",
vModel: "checked",
},
required: false,
})
@@ -63,21 +63,21 @@ export class VoceChatNotification extends BaseNotification {
async send(body: NotificationBody) {
if (!this.apiKey) {
throw new Error('API Key不能为空');
throw new Error("API Key不能为空");
}
if (!this.targetId) {
throw new Error('目标ID不能为空');
throw new Error("目标ID不能为空");
}
const url = this.targetType === 'user' ? '/api/bot/send_to_user/' : '/api/bot/send_to_group/';
const url = this.targetType === "user" ? "/api/bot/send_to_user/" : "/api/bot/send_to_group/";
await this.http.request({
url: url + this.targetId, // 这是示例API URL,请根据实际API文档调整
baseURL: this.endpoint,
method: 'POST',
method: "POST",
headers: {
'x-api-key': this.apiKey,
'Content-Type': 'text/markdown',
"x-api-key": this.apiKey,
"Content-Type": "text/markdown",
},
data: `# ${body.title}\n\n${body.content}\n\n[查看详情](${body.url})`,
skipSslVerify: this.skipSslVerify,
@@ -1,79 +1,79 @@
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from '@certd/pipeline';
import qs from 'qs';
import { BaseNotification, IsNotification, NotificationBody, NotificationInput } from "@certd/pipeline";
import qs from "qs";
@IsNotification({
name: 'webhook',
title: '自定义webhook',
desc: '根据模版自定义http请求',
name: "webhook",
title: "自定义webhook",
desc: "根据模版自定义http请求",
order: -100,
})
export class WebhookNotification extends BaseNotification {
@NotificationInput({
title: 'webhook地址',
title: "webhook地址",
component: {
placeholder: 'https://xxxxx.com/xxxx',
placeholder: "https://xxxxx.com/xxxx",
},
col: {
span: 24,
},
required: true,
})
webhook = '';
webhook = "";
@NotificationInput({
title: '请求方式',
value: 'POST',
title: "请求方式",
value: "POST",
component: {
name: 'a-select',
placeholder: 'post/put/get',
name: "a-select",
placeholder: "post/put/get",
options: [
{ value: 'POST', label: 'POST' },
{ value: 'PUT', label: 'PUT' },
{ value: 'GET', label: 'GET' },
{ value: "POST", label: "POST" },
{ value: "PUT", label: "PUT" },
{ value: "GET", label: "GET" },
],
},
required: true,
})
method = '';
method = "";
@NotificationInput({
title: 'ContentType',
value: 'application/json',
title: "ContentType",
value: "application/json",
component: {
name: 'a-auto-complete',
name: "a-auto-complete",
options: [
{ value: 'application/json', label: 'application/json' },
{ value: 'application/x-www-form-urlencoded', label: 'application/x-www-form-urlencoded' },
{ value: "application/json", label: "application/json" },
{ value: "application/x-www-form-urlencoded", label: "application/x-www-form-urlencoded" },
],
},
helper: '也可以自定义填写',
helper: "也可以自定义填写",
required: true,
})
contentType = '';
contentType = "";
@NotificationInput({
title: 'Headers',
title: "Headers",
component: {
name: 'a-textarea',
vModel: 'value',
name: "a-textarea",
vModel: "value",
rows: 2,
},
col: {
span: 24,
},
helper: '一行一个,格式为key=value',
helper: "一行一个,格式为key=value",
required: false,
})
headers = '';
headers = "";
@NotificationInput({
title: '消息body模版',
title: "消息body模版",
value: `{
"title":"{title}",
"content":"{content}\\n[查看详情]({url})"
}`,
component: {
name: 'a-textarea',
name: "a-textarea",
rows: 4,
},
col: {
@@ -82,14 +82,14 @@ export class WebhookNotification extends BaseNotification {
helper: `根据对应的webhook接口文档,构建一个json对象作为参数(默认值只是一个示例,一般不是正确的参数)\n支持变量:{title}、{content}、{url},变量用{}包裹\n字符串需要双引号,使用\\n换行\n如果是get方式,将作为query参数拼接到url上`,
required: true,
})
template = '';
template = "";
@NotificationInput({
title: '忽略证书校验',
title: "忽略证书校验",
value: false,
component: {
name: 'a-switch',
vModel: 'checked',
name: "a-switch",
vModel: "checked",
},
required: false,
})
@@ -102,17 +102,16 @@ export class WebhookNotification extends BaseNotification {
let value = urlEncode ? encodeURIComponent(body[key]) : body[key];
value = value.replaceAll(`\n`, "\\n");
bodyStr = bodyStr.replaceAll(`{${key}}`, value);
}
return bodyStr;
}
async send(body: NotificationBody) {
if (!this.template) {
throw new Error('模版不能为空');
throw new Error("模版不能为空");
}
if (!this.webhook) {
throw new Error('webhook不能为空');
throw new Error("webhook不能为空");
}
const replaceBody = {
@@ -124,9 +123,9 @@ export class WebhookNotification extends BaseNotification {
let data = JSON.parse(bodyStr);
let url = this.webhook;
if (this.method.toLowerCase() === 'get') {
if (this.method.toLowerCase() === "get") {
const query = qs.stringify(data);
if (url.includes('?')) {
if (url.includes("?")) {
url = `${url}&${query}`;
} else {
url = `${url}?${query}`;
@@ -136,12 +135,12 @@ export class WebhookNotification extends BaseNotification {
const headers: any = {};
if (this.headers && this.headers.trim()) {
this.headers.split('\n').forEach(item => {
this.headers.split("\n").forEach(item => {
item = item.trim();
if (item) {
const eqIndex = item.indexOf('=');
const eqIndex = item.indexOf("=");
if (eqIndex <= 0) {
this.logger.warn('header格式错误,请使用=号分割', item);
this.logger.warn("header格式错误,请使用=号分割", item);
return;
}
const key = item.substring(0, eqIndex);
@@ -155,16 +154,16 @@ export class WebhookNotification extends BaseNotification {
url: url,
method: this.method,
headers: {
'Content-Type': `${this.contentType}; charset=UTF-8`,
"Content-Type": `${this.contentType}; charset=UTF-8`,
...headers,
},
data: data,
skipSslVerify: this.skipSslVerify,
});
return res
return res;
} catch (e) {
if (e.response?.data) {
throw new Error(e.message + ',' + JSON.stringify(e.response.data));
throw new Error(e.message + "," + JSON.stringify(e.response.data));
}
throw e;
}