forked from
leaflet.pub/leaflet
a tool for shared writing and social publishing
1"use server";
2
3import { createClient } from "@supabase/supabase-js";
4import { and, eq, sql } from "drizzle-orm";
5import { drizzle } from "drizzle-orm/node-postgres";
6import {
7 email_subscriptions_to_entity,
8 facts,
9 permission_tokens,
10} from "drizzle/schema";
11import postgres from "postgres";
12import type { Fact } from "src/replicache";
13import { Database } from "supabase/database.types";
14import { pool } from "supabase/pool";
15import { v7 } from "uuid";
16
17export async function confirmEmailSubscription(
18 subscriptionID: string,
19 code: string,
20) {
21 const client = await pool.connect();
22 const db = drizzle(client);
23 let subscription = await db.transaction(async (tx) => {
24 let [{ email_subscriptions_to_entity: sub, permission_tokens: token }] =
25 await db
26 .select()
27 .from(email_subscriptions_to_entity)
28 .innerJoin(
29 permission_tokens,
30 eq(permission_tokens.id, email_subscriptions_to_entity.token),
31 )
32 .where(and(eq(email_subscriptions_to_entity.id, subscriptionID)));
33 if (sub.confirmed) return { subscription: sub, token };
34 if (code !== sub.confirmation_code) return null;
35 let [fact] = (await db
36 .select()
37 .from(facts)
38 .where(
39 and(
40 eq(facts.entity, sub.entity),
41
42 eq(facts.attribute, "mailbox/subscriber-count"),
43 ),
44 )) as Fact<"mailbox/subscriber-count">[];
45 if (!fact) {
46 await db.insert(facts).values({
47 id: v7(),
48 entity: sub.entity,
49 data: sql`${{ type: "number", value: 1 }}::jsonb`,
50 attribute: "mailbox/subscriber-count",
51 });
52 } else {
53 await db
54 .update(facts)
55 .set({
56 data: sql`${{ type: "number", value: fact.data.value + 1 }}::jsonb`,
57 })
58 .where(eq(facts.id, fact.id));
59 }
60 let [subscription] = await db
61 .update(email_subscriptions_to_entity)
62 .set({
63 confirmed: true,
64 })
65 .where(eq(email_subscriptions_to_entity.id, sub.id))
66 .returning();
67
68 return { subscription, token };
69 });
70
71 let supabase = createClient<Database>(
72 process.env.NEXT_PUBLIC_SUPABASE_API_URL as string,
73 process.env.SUPABASE_SERVICE_ROLE_KEY as string,
74 );
75 let channel = supabase.channel(
76 `rootEntity:${subscription?.token.root_entity}`,
77 );
78 await channel.send({
79 type: "broadcast",
80 event: "poke",
81 payload: { message: "poke" },
82 });
83 supabase.removeChannel(channel);
84 client.release();
85 return subscription;
86}