Working on notification system.

This commit is contained in:
charlesgauthereau
2025-12-06 23:14:59 +01:00
parent 9458b12d69
commit fde7688485
64 changed files with 792 additions and 551 deletions
+11 -2
View File
@@ -1,9 +1,10 @@
import {boolean, jsonb, pgEnum, pgTable, primaryKey, unique, uuid, varchar} from "drizzle-orm/pg-core";
import {timestamps} from "@/db/schema/00_common";
import {organization} from "@/db/schema/03_organization";
import {MemberWithUser, Organization, organization} from "@/db/schema/03_organization";
import {relations} from "drizzle-orm";
import {createSelectSchema} from "drizzle-zod";
import {z} from "zod";
import {OrganizationInvitation} from "@/db/schema/05_invitation";
export const providerKindEnum = pgEnum('provider_kind', ['slack', 'smtp']);
@@ -47,4 +48,12 @@ export const organizationNotificationChannelRelations = relations(organizationNo
}));
export const notificationChannelSchema = createSelectSchema(notificationChannel);
export type NotificationChannel = z.infer<typeof notificationChannelSchema>;
export type NotificationChannel = z.infer<typeof notificationChannelSchema>;
export type NotificationChannelWith = NotificationChannel & {
organizations: {
organizationId: string;
notificationChannelId: string;
}[];
};
+15 -6
View File
@@ -1,8 +1,11 @@
import {pgTable, uuid, timestamp, jsonb, varchar, boolean, text, pgEnum} from 'drizzle-orm/pg-core';
import {notificationChannel, providerKindEnum} from "@/db/schema/09_notification-channel";
import {notificationChannel} from "@/db/schema/09_notification-channel";
import {alertPolicy} from "@/db/schema/10_alert-policy";
import {organization} from "@/db/schema/03_organization";
import {timestamps} from "@/db/schema/00_common";
import {createSelectSchema} from "drizzle-zod";
import {z} from "zod";
export const levelEnum = pgEnum('level', ['critical', 'warning', 'info']);
@@ -12,21 +15,27 @@ export const notificationLog = pgTable('notification_log', {
channelId: uuid('channel_id')
.notNull()
.references(() => notificationChannel.id, { onDelete: 'restrict' }),
.references(() => notificationChannel.id, {onDelete: 'restrict'}),
policyId: uuid('policy_id')
.references(() => alertPolicy.id, { onDelete: 'restrict' }),
.references(() => alertPolicy.id, {onDelete: 'restrict'}),
organizationId: uuid('organization_id')
.references(() => organization.id, { onDelete: 'set null' }),
.references(() => organization.id, {onDelete: 'set null'}),
title: varchar('title', { length: 255 }).notNull(),
title: varchar('title', {length: 255}).notNull(),
message: text('message').notNull(),
level: levelEnum('level').notNull(),
payload: jsonb('payload'),
success: boolean('success').notNull(),
error: text('error'),
providerResponse: jsonb('provider_response'),
sentAt: timestamp('sent_at').defaultNow().notNull(),
...timestamps
});
});
export const notificationLogSchema = createSelectSchema(notificationLog);
export type NotificationLog = z.infer<typeof notificationLogSchema>;
export type NotificationLevel = (typeof levelEnum.enumValues)[number];
+52 -21
View File
@@ -1,24 +1,45 @@
import {desc, eq, and, gte, lte} from 'drizzle-orm';
import {
notificationLog
} from "@/db/schema/11_notification-log";
import {
notificationChannel,
} from "@/db/schema/09_notification-channel";
import {and, desc, eq, gte, lte} from 'drizzle-orm';
import {NotificationLevel, notificationLog} from "@/db/schema/11_notification-log";
import {notificationChannel} from "@/db/schema/09_notification-channel";
import {db} from "@/db";
import {alertPolicy} from "@/db/schema/10_alert-policy";
import {Json} from "drizzle-zod";
export type NotificationLogWithRelations = {
id: string;
title: string;
level: NotificationLevel;
success: boolean;
error: string | null;
sentAt: Date;
payload: Json | null;
content: {
title: string;
message: string;
},
channel: {
id: string;
name: string;
provider: string;
} | null;
policy: {
id: string;
eventKinds: string[];
} | null;
};
export async function getNotificationHistory(filters?: {
channelId?: string;
policyId?: string;
organizationId?: string;
level?: string;
success?: boolean;
from?: Date;
to?: Date;
limit?: number;
}) {
export async function getNotificationHistory(
filters?: {
channelId?: string;
policyId?: string;
organizationId?: string;
level?: NotificationLevel;
success?: boolean;
from?: Date;
to?: Date;
limit?: number;
}
): Promise<NotificationLogWithRelations[]> {
const where = [];
if (filters?.channelId) where.push(eq(notificationLog.channelId, filters.channelId));
if (filters?.policyId) where.push(eq(notificationLog.policyId, filters.policyId));
@@ -28,7 +49,7 @@ export async function getNotificationHistory(filters?: {
if (filters?.from) where.push(gte(notificationLog.sentAt, filters.from));
if (filters?.to) where.push(lte(notificationLog.sentAt, filters.to));
return await db
const rows = await db
.select({
id: notificationLog.id,
title: notificationLog.title,
@@ -36,14 +57,19 @@ export async function getNotificationHistory(filters?: {
success: notificationLog.success,
error: notificationLog.error,
sentAt: notificationLog.sentAt,
payload: notificationLog.payload,
content: {
title: notificationLog.title,
message: notificationLog.message,
},
channel: {
id: notificationLog.id,
id: notificationChannel.id,
name: notificationChannel.name,
provider: notificationChannel.provider,
},
policy: {
id: alertPolicy.id,
eventKind: alertPolicy.eventKind,
eventKinds: alertPolicy.eventKinds,
},
})
.from(notificationLog)
@@ -52,4 +78,9 @@ export async function getNotificationHistory(filters?: {
.where(and(...where))
.orderBy(desc(notificationLog.sentAt))
.limit(filters?.limit || 100);
}
return rows.map(row => ({
...row,
payload: row.payload as Json,
}));
}