feat(notifications) : notify guide publications and admin hearts; simplify Stygian navigation
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import "server-only";
|
||||
|
||||
import { and, asc, eq, gt, isNull, lte, sql } from "drizzle-orm";
|
||||
import { getDb } from "@/db";
|
||||
import { guides, users } from "@/db/schema";
|
||||
import type { OutboxEventLike } from "@/lib/events/invalidation";
|
||||
import { createNotifications } from "@/lib/notifications/repository";
|
||||
|
||||
export async function sendGuidePublicationNotifications(event: OutboxEventLike) {
|
||||
const publishedAt = typeof event.payload.publishedAt === "string"
|
||||
? new Date(event.payload.publishedAt) : null;
|
||||
if (event.eventType !== "guide.published" || event.topic !== "notifications:guide"
|
||||
|| !publishedAt || Number.isNaN(publishedAt.getTime())) {
|
||||
throw new Error("Invalid guide publication notification event");
|
||||
}
|
||||
const db = getDb();
|
||||
const [guide] = await db.select({ name: guides.name, slug: guides.slug }).from(guides)
|
||||
.where(and(eq(guides.id, event.aggregateId), eq(guides.isPublic, true), isNull(guides.trashedAt))).limit(1);
|
||||
if (!guide) return;
|
||||
|
||||
let cursor: string | undefined;
|
||||
while (true) {
|
||||
const recipients: { id: string }[] = await db.select({ id: users.id }).from(users)
|
||||
.where(and(sql`${users.banned} is not true`, lte(users.createdAt, publishedAt),
|
||||
cursor === undefined ? undefined : gt(users.id, cursor)))
|
||||
.orderBy(asc(users.id)).limit(100);
|
||||
if (!recipients.length) return;
|
||||
await createNotifications(recipients.map(user => ({ userId: user.id, url: `/${guide.slug}` })), {
|
||||
eventKey: `guide:${event.aggregateId}:published`,
|
||||
kind: "guide_published",
|
||||
title: "เผยแพร่ Guide ใหม่",
|
||||
body: `อ่าน Guide ${guide.name} ได้แล้ว`,
|
||||
});
|
||||
cursor = recipients[recipients.length - 1].id;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user