Add automated ISAC system notifications
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { getDatabase } from '$lib/server/database';
|
||||
import { createNotification } from '$lib/server/notifications';
|
||||
|
||||
export const AUTOMATED_MESSAGE_EVENTS = [
|
||||
{ value: 'account.created', label: 'ACCOUNT CREATED', description: 'After a new SHD.build account is created' }
|
||||
] as const;
|
||||
export type AutomatedMessageEvent = (typeof AUTOMATED_MESSAGE_EVENTS)[number]['value'];
|
||||
|
||||
type MessageRow = Record<string, unknown>;
|
||||
|
||||
function parseActions(value: unknown): Array<{ label: string; href: string }> {
|
||||
try {
|
||||
const parsed = JSON.parse(String(value ?? '[]'));
|
||||
if (!Array.isArray(parsed)) return [];
|
||||
return parsed
|
||||
.filter((item) => item && typeof item.label === 'string' && typeof item.href === 'string')
|
||||
.map((item) => ({ label: item.label.slice(0, 60), href: item.href.slice(0, 500) }))
|
||||
.slice(0, 8);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function deliver(message: MessageRow, deliveryId: string, userId: string) {
|
||||
const notificationId = await createNotification({
|
||||
userId,
|
||||
category: 'isac',
|
||||
source: String(message.source),
|
||||
title: String(message.title),
|
||||
body: String(message.body),
|
||||
link: typeof message.link === 'string' ? message.link : null,
|
||||
actions: parseActions(message.actions_json),
|
||||
mandatory: true
|
||||
});
|
||||
if (!notificationId) return;
|
||||
const database = await getDatabase();
|
||||
await (await database.prepare(`UPDATE automated_system_message_deliveries
|
||||
SET delivered_at=?,notification_id=? WHERE id=? AND delivered_at IS NULL`))
|
||||
.run(new Date().toISOString(), notificationId, deliveryId);
|
||||
}
|
||||
|
||||
export async function triggerAutomatedSystemMessages(input: {
|
||||
eventKey: AutomatedMessageEvent;
|
||||
userId: string;
|
||||
eventId: string;
|
||||
}) {
|
||||
const database = await getDatabase();
|
||||
const messages = await (await database.prepare(
|
||||
'SELECT * FROM automated_system_messages WHERE event_key=? AND enabled=1 ORDER BY name'
|
||||
)).all(input.eventKey);
|
||||
const now = new Date();
|
||||
for (const message of messages) {
|
||||
const existing = await (await database.prepare(`SELECT id FROM automated_system_message_deliveries
|
||||
WHERE message_id=? AND user_id=? AND event_key=? AND event_id=?`))
|
||||
.get(message.id, input.userId, input.eventKey, input.eventId);
|
||||
if (existing) continue;
|
||||
const deliveryId = randomUUID();
|
||||
const scheduledFor = new Date(now.getTime() + Number(message.send_delay_minutes ?? 0) * 60_000);
|
||||
await (await database.prepare(`INSERT OR IGNORE INTO automated_system_message_deliveries
|
||||
(id,message_id,user_id,event_key,event_id,scheduled_for,created_at)
|
||||
VALUES(?,?,?,?,?,?,?)`)).run(
|
||||
deliveryId, message.id, input.userId, input.eventKey, input.eventId,
|
||||
scheduledFor.toISOString(), now.toISOString()
|
||||
);
|
||||
if (Number(message.send_delay_minutes ?? 0) === 0) {
|
||||
await deliver(message, deliveryId, input.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ export async function createNotification(input: {
|
||||
title: string;
|
||||
body: string;
|
||||
link?: string | null;
|
||||
actions?: Array<{ label: string; href: string }>;
|
||||
mandatory?: boolean;
|
||||
}) {
|
||||
const database = await getDatabase();
|
||||
@@ -26,10 +27,12 @@ export async function createNotification(input: {
|
||||
const id = randomUUID();
|
||||
const now = new Date().toISOString();
|
||||
await (await database.prepare(`INSERT INTO notifications
|
||||
(id,user_id,category,source,title,body,link,mandatory,created_at)
|
||||
VALUES(?,?,?,?,?,?,?,?,?)`)).run(
|
||||
(id,user_id,category,source,title,body,link,actions_json,mandatory,created_at)
|
||||
VALUES(?,?,?,?,?,?,?,?,?,?)`)).run(
|
||||
id, input.userId, input.category, input.source, input.title.slice(0, 140),
|
||||
input.body.slice(0, 2000), input.link ?? null, mandatory ? 1 : 0, now
|
||||
input.body.slice(0, 2000), input.link ?? null,
|
||||
input.actions?.length ? JSON.stringify(input.actions.slice(0, 8)) : null,
|
||||
mandatory ? 1 : 0, now
|
||||
);
|
||||
if (emailFrequency === 'immediate') {
|
||||
const identity = await (await database.prepare('SELECT email FROM user_emails WHERE user_id=?')).get(input.userId);
|
||||
|
||||
Reference in New Issue
Block a user