🚧 process test alert

This commit is contained in:
Fred KISSIE
2026-08-07 20:52:25 +02:00
parent 6689a8d93e
commit 3f305e4d5c
5 changed files with 89 additions and 11 deletions
@@ -0,0 +1,22 @@
import logger from "@server/logger";
import type { TestAlertContext } from "@server/routers/alertRule/types";
import { sendAlertEmail } from "./sendAlertEmail";
export async function processTestAlerts(context: TestAlertContext) {
const emailActions = context.actions.filter(
(action) => action.type === "email"
);
// Process email actions
for (const action of emailActions) {
try {
const recipients = await resolveEmailRecipients(
action.emailActionId
);
if (recipients.length > 0) {
await sendAlertEmail(recipients, context);
}
} catch (err) {
logger.error(`processAlerts: failed to send alert email`, err);
}
}
}
+1 -1
View File
@@ -16,4 +16,4 @@ export * from "./updateAlertRule";
export * from "./deleteAlertRule"; export * from "./deleteAlertRule";
export * from "./listAlertRules"; export * from "./listAlertRules";
export * from "./getAlertRule"; export * from "./getAlertRule";
export * from "./testSiteAlertRule"; export * from "./testAlertRule";
@@ -33,11 +33,44 @@ const paramsSchema = z.strictObject({
orgId: z.string().nonempty() orgId: z.string().nonempty()
}); });
const querySchema = z.strictObject({ export const SITE_EVENT_TYPES = [
event: z.enum(["site_offline", "site_online", "site_toggle"]) "site_online",
"site_offline",
"site_toggle"
] as const;
export const HC_EVENT_TYPES = [
"health_check_healthy",
"health_check_unhealthy",
"health_check_toggle"
] as const;
export const RESOURCE_EVENT_TYPES = [
"resource_healthy",
"resource_unhealthy",
"resource_degraded",
"resource_toggle"
] as const;
const webhookActionSchema = z.strictObject({
webhookUrl: z.string().url(),
config: z.string().optional(),
enabled: z.boolean().optional().default(true)
}); });
export async function testSiteAlertRule( const bodySchema = z.strictObject({
eventType: z.enum([
...HC_EVENT_TYPES,
...SITE_EVENT_TYPES,
...RESOURCE_EVENT_TYPES
]),
// Email recipients (flat)
userIds: z.array(z.string().nonempty()).optional().default([]),
roleIds: z.array(z.number()).optional().default([]),
emails: z.array(z.email()).optional().default([]),
// Webhook actions
webhookActions: z.array(webhookActionSchema).optional().default([])
});
export async function testAlertRule(
req: Request, req: Request,
res: Response, res: Response,
next: NextFunction next: NextFunction
@@ -54,16 +87,17 @@ export async function testSiteAlertRule(
} }
const { orgId } = parsedParams.data; const { orgId } = parsedParams.data;
const parsedQuery = querySchema.safeParse(req.query); const parsedBody = bodySchema.safeParse(req.body);
if (!parsedQuery.success) { if (!parsedBody.success) {
return next( return next(
createHttpError( createHttpError(
HttpCode.BAD_REQUEST, HttpCode.BAD_REQUEST,
fromError(parsedQuery.error).toString() fromError(parsedBody.error).toString()
) )
); );
} }
const { event } = parsedQuery.data;
// TODO: process alert rule
} catch (error) { } catch (error) {
logger.error(error); logger.error(error);
return next( return next(
+3 -3
View File
@@ -808,12 +808,12 @@ authenticated.get(
alertRule.listAlertRules alertRule.listAlertRules
); );
authenticated.get( authenticated.post(
"/org/:orgId/test-site-alert-rule/:alertRuleId", "/org/:orgId/alert-rule/test",
verifyValidLicense, verifyValidLicense,
verifyOrgAccess, verifyOrgAccess,
verifyUserHasAction(ActionsEnum.testAlertRule), verifyUserHasAction(ActionsEnum.testAlertRule),
alertRule.testSiteAlertRule alertRule.testAlertRule
); );
authenticated.get( authenticated.get(
+22
View File
@@ -124,3 +124,25 @@ export interface AlertContext {
/** Human-readable context data included in emails and webhook payloads */ /** Human-readable context data included in emails and webhook payloads */
data: Record<string, unknown>; data: Record<string, unknown>;
} }
type EmailAlertAction = {
type: "email";
userIds?: string[];
roleIds?: string[];
emails?: string[];
};
type WebhookAlertAction = {
type: "webhook";
webhookUrl: string;
enabled: boolean;
config?: string | undefined;
};
type AlertAction = EmailAlertAction | WebhookAlertAction;
export interface TestAlertContext {
eventType: AlertEventType;
actions: AlertAction[];
/** Human-readable context data included in emails and webhook payloads */
data: Record<string, unknown>;
}