From de9e9ce6270dce69c315508f42073bd02861cf35 Mon Sep 17 00:00:00 2001 From: whyour Date: Wed, 22 Nov 2023 22:43:48 +0800 Subject: [PATCH] =?UTF-8?q?webhook=20=E9=80=9A=E7=9F=A5=20body=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20text/plain=20=E7=B1=BB=E5=9E=8B=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=A4=9A=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E9=87=8D=E5=90=AF=E6=9C=AA=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- back/config/util.ts | 11 ++++++++--- back/services/cron.ts | 16 ++++++++-------- back/services/notify.ts | 5 ++++- sample/config.sample.sh | 7 +++---- sample/notify.js | 4 +++- sample/notify.py | 4 ++-- src/utils/config.ts | 1 + 7 files changed, 29 insertions(+), 19 deletions(-) diff --git a/back/config/util.ts b/back/config/util.ts index 708ad360..abd2423d 100644 --- a/back/config/util.ts +++ b/back/config/util.ts @@ -61,7 +61,8 @@ export async function getNetIp(req: any) { ...req.ips, req.socket.remoteAddress, ]), - ]; + ].filter(Boolean); + let ip = ipArray[0]; if (ipArray.length > 1) { @@ -82,6 +83,7 @@ export async function getNetIp(req: any) { break; } } + ip = ip.substr(ip.lastIndexOf(':') + 1, ip.length); if (ip.includes('127.0') || ip.includes('192.168') || ip.includes('10.7')) { ip = ''; @@ -347,9 +349,12 @@ export function parseBody( contentType: | 'application/json' | 'multipart/form-data' - | 'application/x-www-form-urlencoded', + | 'application/x-www-form-urlencoded' + | 'text/plain', ) { - if (!body) return ''; + if (contentType === 'text/plain' || !body) { + return body; + } const parsed: any = {}; let key; diff --git a/back/services/cron.ts b/back/services/cron.ts index a1b36079..f6e55fa4 100644 --- a/back/services/cron.ts +++ b/back/services/cron.ts @@ -26,9 +26,9 @@ import omit from 'lodash/omit'; export default class CronService { constructor(@Inject('logger') private logger: winston.Logger) {} - private isSixCron(cron: Crontab) { - const { schedule } = cron; - if (Number(schedule?.split(/ +/).length) > 5) { + private isNodeCron(cron: Crontab) { + const { schedule, extra_schedules } = cron; + if (Number(schedule?.split(/ +/).length) > 5 || extra_schedules?.length) { return true; } return false; @@ -38,7 +38,7 @@ export default class CronService { const tab = new Crontab(payload); tab.saved = false; const doc = await this.insert(tab); - if (this.isSixCron(doc) || doc.extra_schedules?.length) { + if (this.isNodeCron(doc)) { await cronClient.addCron([ { name: doc.name || '', @@ -65,10 +65,10 @@ export default class CronService { if (doc.isDisabled === 1) { return newDoc; } - if (this.isSixCron(doc) || doc.extra_schedules?.length) { + if (this.isNodeCron(doc)) { await cronClient.delCron([String(doc.id)]); } - if (this.isSixCron(newDoc) || newDoc.extra_schedules?.length) { + if (this.isNodeCron(newDoc)) { await cronClient.addCron([ { name: doc.name || '', @@ -472,7 +472,7 @@ export default class CronService { await CrontabModel.update({ isDisabled: 0 }, { where: { id: ids } }); const docs = await CrontabModel.findAll({ where: { id: ids } }); const sixCron = docs - .filter((x) => this.isSixCron(x)) + .filter((x) => this.isNodeCron(x)) .map((doc) => ({ name: doc.name || '', id: String(doc.id), @@ -613,7 +613,7 @@ export default class CronService { this.set_crontab(tabs); const sixCron = tabs.data - .filter((x) => this.isSixCron(x) && x.isDisabled !== 1) + .filter((x) => this.isNodeCron(x) && x.isDisabled !== 1) .map((doc) => ({ name: doc.name || '', id: String(doc.id), diff --git a/back/services/notify.ts b/back/services/notify.ts index f80c0b98..9962ddf2 100644 --- a/back/services/notify.ts +++ b/back/services/notify.ts @@ -659,9 +659,11 @@ export default class NotificationService { webhookUrl, webhookBody, ); + if (!formatUrl && !formatBody) { - return false; + throw new Error('Url 或者 Body 中必须包含 $title') } + const headers = parseHeaders(webhookHeaders); const body = parseBody(formatBody, webhookContentType); const bodyParam = this.formatBody(webhookContentType, body); @@ -692,6 +694,7 @@ export default class NotificationService { case 'multipart/form-data': return { form: body }; case 'application/x-www-form-urlencoded': + case 'text/plain': return { body }; } return {}; diff --git a/sample/config.sample.sh b/sample/config.sample.sh index 6771b2c2..5e163d49 100644 --- a/sample/config.sample.sh +++ b/sample/config.sample.sh @@ -21,8 +21,7 @@ DiskWarn=90 ## 设置定时任务执行的超时时间,例如1h,后缀"s"代表秒(默认值), "m"代表分, "h"代表小时, "d"代表天 CommandTimeoutTime="" -## 在运行 task 命令时,随机延迟启动任务的最大延迟时间 -## 默认给javascript任务加随机延迟,如 RandomDelay="300" ,表示任务将在 1-300 秒内随机延迟一个秒数,然后再运行,取消延迟赋值为空 +## 在运行 task 命令时,随机延迟启动任务的最大延迟时间,如 RandomDelay="300" ,表示任务将在 1-300 秒内随机延迟一个秒数,然后再运行,取消延迟赋值为空 RandomDelay="" ## 需要随机延迟运行任务的文件后缀,直接写后缀名即可,多个后缀用空格分开,例如: js py ts @@ -33,8 +32,8 @@ RandomDelayFileExtensions="" ## 默认是第0分钟和第30分钟,例如21:00或21:30分的任务将会准点运行。不需要准点运行赋值为空 RandomDelayIgnoredMinutes="" -## 如果你自己会写shell脚本,并且希望在每次运行 ql update 命令时,额外运行你的 shell 脚本,请赋值为 "true",默认为true -EnableExtraShell="true" +## 如果你自己会写shell脚本,并且希望在每次容器启动时,额外运行你的 shell 脚本,请赋值为 "true" +EnableExtraShell="" ## 是否自动启动bot,默认不启动,设置为true时自动启动,目前需要自行克隆bot仓库所需代码,存到ql/repo目录下,文件夹命名为dockerbot AutoStartBot="" diff --git a/sample/notify.js b/sample/notify.js index 3cf5eca5..ea140c04 100644 --- a/sample/notify.js +++ b/sample/notify.js @@ -1350,7 +1350,9 @@ function parseHeaders(headers) { } function parseBody(body, contentType) { - if (!body) return ''; + if (contentType === 'text/plain' || !body) { + return body; + } const parsed = {}; let key; diff --git a/sample/notify.py b/sample/notify.py index aa53f28b..25df2f97 100644 --- a/sample/notify.py +++ b/sample/notify.py @@ -749,8 +749,8 @@ def parse_headers(headers): def parse_body(body, content_type): - if not body: - return "" + if not body or content_type == "text/plain": + return body parsed = {} lines = body.split("\n") diff --git a/src/utils/config.ts b/src/utils/config.ts index f7f05eae..d8bf3893 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -369,6 +369,7 @@ export default { tip: intl.get('请求头Content-Type'), required: true, items: [ + { value: 'text/plain' }, { value: 'application/json' }, { value: 'multipart/form-data' }, { value: 'application/x-www-form-urlencoded' },