From 7b95c55a70c290eba4bef464589fc406536b0354 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Fri, 3 May 2024 00:30:23 +0800 Subject: [PATCH] feat: add cronjob for send https certificate expired notification --- .../components/monitor/MonitorStatsBlock.tsx | 9 +- .../components/monitor/provider/http.tsx | 7 ++ src/client/i18next-toolkit.config.cjs | 4 +- src/client/public/locales/de/translation.json | 1 + src/client/public/locales/en/translation.json | 1 + src/client/public/locales/fr/translation.json | 1 + src/client/public/locales/jp/translation.json | 3 +- src/client/public/locales/pl/translation.json | 1 + src/client/public/locales/pt/translation.json | 1 + src/client/public/locales/ru/translation.json | 1 + src/client/public/locales/zh/translation.json | 1 + src/server/cronjob/index.ts | 88 +++++++++++++++++-- 12 files changed, 109 insertions(+), 9 deletions(-) diff --git a/src/client/components/monitor/MonitorStatsBlock.tsx b/src/client/components/monitor/MonitorStatsBlock.tsx index d5e662fa..ced296de 100644 --- a/src/client/components/monitor/MonitorStatsBlock.tsx +++ b/src/client/components/monitor/MonitorStatsBlock.tsx @@ -1,7 +1,9 @@ import React from 'react'; +import { TipIcon } from '../TipIcon'; interface MonitorStatsBlockProps { title: string; + tooltip?: string; desc: string; text: string; } @@ -9,7 +11,12 @@ export const MonitorStatsBlock: React.FC = React.memo( (props) => { return (
-
{props.title}
+
+ {props.title} + {props.tooltip && ( + + )} +
{props.desc}
{props.text}
diff --git a/src/client/components/monitor/provider/http.tsx b/src/client/components/monitor/provider/http.tsx index 76e5f272..86a923da 100644 --- a/src/client/components/monitor/provider/http.tsx +++ b/src/client/components/monitor/provider/http.tsx @@ -30,9 +30,13 @@ const MonitorHttp: React.FC = React.memo(() => { }, }, ]} + tooltip={t( + 'For HTTPS monitoring, if any notification method is assigned, notifications will be sent at 1, 3, 7 and 14 days before expiration.' + )} > + ` + SELECT "monitorId", (payload -> 'certInfo' ->> 'daysRemaining')::int as "daysRemaining" + FROM "MonitorStatus" + WHERE "statusName" = 'tls' + AND "updatedAt" >= now() - interval '1 day' + AND (payload -> 'certInfo' ->> 'daysRemaining')::int in (1, 3, 7, 14); + `; + + logger.info(`[dailyHTTPCertCheckNotify] find ${res.length} records`); + + const monitors = await prisma.monitor.findMany({ + where: { + id: { + in: res.map((r) => r.monitorId), + }, + }, + include: { + notifications: true, + }, + }); + + let sendCount = 0; + + for (const m of monitors) { + if (m.active === false) { + continue; + } + + for (const n of m.notifications) { + const daysRemaining = res.find( + (item) => item.monitorId === m.id + )?.daysRemaining; + if (!daysRemaining) { + continue; + } + + const content = `[${m.name}][${_.get(m.payload, 'url')}] Certificate will be expired in ${daysRemaining} days`; + + try { + await sendNotification(n, content, [token.text(content)]).catch( + logger.error + ); + sendCount++; + } catch (err) { + logger.error(err); + } + } + } + + logger.info( + `[dailyHTTPCertCheckNotify] run completed, send ${sendCount} notifications, time usage: ${Date.now() - start}ms` + ); }