a tool for shared writing and social publishing
1"use server"; 2import { drizzle } from "drizzle-orm/node-postgres"; 3import postgres from "postgres"; 4import { 5 email_auth_tokens, 6 identities, 7 entity_sets, 8 entities, 9 permission_tokens, 10 permission_token_rights, 11 permission_token_on_homepage, 12 poll_votes_on_entity, 13} from "drizzle/schema"; 14import { and, eq, isNull } from "drizzle-orm"; 15import { cookies } from "next/headers"; 16import { redirect } from "next/navigation"; 17import { v7 } from "uuid"; 18import { createIdentity } from "./createIdentity"; 19import { pool } from "supabase/pool"; 20 21export async function loginWithEmailToken( 22 localLeaflets: { token: { id: string }; added_at: string }[], 23) { 24 const client = await pool.connect(); 25 const db = drizzle(client); 26 let token_id = (await cookies()).get("auth_token")?.value; 27 let voter_token = (await cookies()).get("poll_voter_token")?.value; 28 if (!token_id) return null; 29 let result = await db.transaction(async (tx) => { 30 let [token] = await tx 31 .select() 32 .from(email_auth_tokens) 33 .where( 34 and( 35 eq(email_auth_tokens.id, token_id), 36 eq(email_auth_tokens.confirmed, true), 37 ), 38 ); 39 if (!token || !token.email) return null; 40 if (token.identity) { 41 let id = token.identity; 42 if (localLeaflets.length > 0) 43 await tx 44 .insert(permission_token_on_homepage) 45 .values( 46 localLeaflets.map((l) => ({ 47 identity: id, 48 token: l.token.id, 49 })), 50 ) 51 .onConflictDoNothing(); 52 return token; 53 } 54 let [existingIdentity] = await tx 55 .select() 56 .from(identities) 57 .where(eq(identities.email, token.email)); 58 59 let identity = existingIdentity; 60 if (!existingIdentity) { 61 let identityCookie = (await cookies()).get("identity"); 62 if (identityCookie) { 63 let [existingIdentityFromCookie] = await tx 64 .select() 65 .from(identities) 66 .where( 67 and( 68 eq(identities.id, identityCookie.value), 69 isNull(identities.email), 70 ), 71 ); 72 if (existingIdentityFromCookie) { 73 await tx 74 .update(identities) 75 .set({ email: token.email }) 76 .where(eq(identities.id, existingIdentityFromCookie.id)); 77 identity = existingIdentityFromCookie; 78 } 79 } else { 80 // Create a new identity 81 identity = await createIdentity(tx, { email: token.email }); 82 } 83 } 84 85 await tx 86 .update(email_auth_tokens) 87 .set({ identity: identity.id }) 88 .where(eq(email_auth_tokens.id, token_id)); 89 90 if (localLeaflets.length > 0) 91 await tx 92 .insert(permission_token_on_homepage) 93 .values( 94 localLeaflets.map((l) => ({ 95 identity: identity.id, 96 token: l.token.id, 97 })), 98 ) 99 .onConflictDoNothing(); 100 101 return token; 102 }); 103 if (result?.identity) { 104 if (result.identity !== voter_token) { 105 if (voter_token) 106 await db 107 .update(poll_votes_on_entity) 108 .set({ voter_token: result.identity }) 109 .where(eq(poll_votes_on_entity.voter_token, voter_token)); 110 111 (await cookies()).set("poll_voter_token", result.identity, { 112 maxAge: 60 * 60 * 24 * 365, 113 secure: process.env.NODE_ENV === "production", 114 httpOnly: true, 115 sameSite: "lax", 116 }); 117 } 118 } 119 client.release(); 120}