mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Working on notifier system.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"use server"
|
||||
// src/notifications/dispatch.ts
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { dispatchViaProvider } from './providers';
|
||||
import type { EventPayload, DispatchResult } from './types';
|
||||
import * as drizzleDb from "@/db";
|
||||
import {db} from "@/db";
|
||||
|
||||
export async function dispatchNotification(
|
||||
payload: EventPayload,
|
||||
policyId?: string,
|
||||
channelId?: string,
|
||||
): Promise<DispatchResult> {
|
||||
|
||||
// // 1. Get policy + channel
|
||||
// const policy = await db
|
||||
// .select({
|
||||
// policy: alertPolicies,
|
||||
// channel: notificationChannels,
|
||||
// })
|
||||
// .from(alertPolicies)
|
||||
// .innerJoin(
|
||||
// notificationChannels,
|
||||
// eq(alertPolicies.notificationChannelId, notificationChannels.id)
|
||||
// )
|
||||
// .where(eq(alertPolicies.id, policyId))
|
||||
// .then((rows) => rows[0]);
|
||||
//
|
||||
// if (!policy) {
|
||||
// return {
|
||||
// success: false,
|
||||
// channelId: '',
|
||||
// provider: 'unknown' as any,
|
||||
// error: 'Policy or channel not found',
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// if (!policy.policy.enabled || !policy.channel.enabled) {
|
||||
// return {
|
||||
// success: false,
|
||||
// channelId: policy.channel.id,
|
||||
// provider: policy.channel.provider as any,
|
||||
// error: 'Policy or channel is disabled',
|
||||
// };
|
||||
// }
|
||||
|
||||
if (channelId){
|
||||
const channel = await db.query.notificationChannel.findFirst({
|
||||
where: eq(drizzleDb.schemas.notificationChannel.id, channelId),
|
||||
})
|
||||
|
||||
if (channel){
|
||||
const config = channel.config;
|
||||
|
||||
const result = await dispatchViaProvider(
|
||||
channel.provider as any,
|
||||
config,
|
||||
{ ...payload, timestamp: payload.timestamp || new Date() },
|
||||
channel.id
|
||||
);
|
||||
|
||||
return {
|
||||
...result,
|
||||
channelId: channel.id,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
channelId,
|
||||
provider: "smtp",
|
||||
error: 'Unknown error',
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
"use server"
|
||||
import type { ProviderKind, EventPayload, DispatchResult } from '../types';
|
||||
// import { sendSlack } from './slack';
|
||||
import { sendSmtp } from './smtp';
|
||||
|
||||
const handlers: Record<
|
||||
ProviderKind,
|
||||
(config: any, payload: EventPayload) => Promise<DispatchResult>
|
||||
> = {
|
||||
// slack: sendSlack,
|
||||
smtp: sendSmtp,
|
||||
};
|
||||
|
||||
export async function dispatchViaProvider(
|
||||
kind: ProviderKind,
|
||||
config: any,
|
||||
payload: EventPayload,
|
||||
channelId: string
|
||||
): Promise<DispatchResult> {
|
||||
const handler = handlers[kind];
|
||||
if (!handler) {
|
||||
return {
|
||||
success: false,
|
||||
channelId,
|
||||
provider: kind,
|
||||
error: `Unsupported provider: ${kind}`,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
return await handler(config, payload);
|
||||
} catch (err: any) {
|
||||
return {
|
||||
success: false,
|
||||
channelId,
|
||||
provider: kind,
|
||||
error: err.message || 'Unknown error',
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
"use server"
|
||||
import type {EventPayload, DispatchResult} from '../types';
|
||||
import nodemailer from 'nodemailer';
|
||||
import {render} from "@react-email/render";
|
||||
import TestEmailSettings from "../../../../emails/TestEmailSettings";
|
||||
|
||||
export async function sendSmtp(
|
||||
config: {
|
||||
host: string;
|
||||
port: number;
|
||||
secure: boolean;
|
||||
user: string;
|
||||
password: string;
|
||||
from: string;
|
||||
to: string | string[];
|
||||
},
|
||||
payload: EventPayload
|
||||
): Promise<DispatchResult> {
|
||||
console.log(config)
|
||||
const transporter = nodemailer.createTransport({
|
||||
pool: true,
|
||||
host: config.host,
|
||||
port: config.port,
|
||||
// secure: config.secure,
|
||||
secure: true,
|
||||
auth: {user: config.user, pass: config.password},
|
||||
});
|
||||
|
||||
|
||||
|
||||
const result = await transporter.verify();
|
||||
console.log(result);
|
||||
|
||||
const html = `
|
||||
<h2>${payload.title}</h2>
|
||||
<p><strong>Level:</strong> ${payload.level}</p>
|
||||
<p>${payload.message.replace(/\n/g, '<br>')}</p>
|
||||
${payload.data ? `<pre>${JSON.stringify(payload.data, null, 2)}</pre>` : ''}
|
||||
`;
|
||||
|
||||
const info = await transporter.sendMail({
|
||||
from: config.from,
|
||||
to: Array.isArray(config.to) ? config.to.join(', ') : config.to,
|
||||
// to: config.from,
|
||||
subject: `[${payload.level.toUpperCase()}] ${payload.title}`,
|
||||
html,
|
||||
// subject: "Portabase",
|
||||
// html: await render(TestEmailSettings(), {}),
|
||||
});
|
||||
|
||||
console.log(info);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
provider: 'smtp',
|
||||
message: `Email sent: ${info.messageId}`,
|
||||
response: info,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// export type ProviderKind = 'slack' | 'smtp';
|
||||
export type ProviderKind = 'smtp';
|
||||
|
||||
export interface DispatchResult {
|
||||
success: boolean;
|
||||
channelId?: string;
|
||||
provider: ProviderKind;
|
||||
message?: string;
|
||||
error?: string;
|
||||
response?: any;
|
||||
}
|
||||
|
||||
export interface EventPayload {
|
||||
title: string;
|
||||
message: string;
|
||||
level: 'critical' | 'warning' | 'info';
|
||||
timestamp?: Date;
|
||||
data?: Record<string, any>;
|
||||
}
|
||||
Reference in New Issue
Block a user