"use server"; import { createServerClient } from "@supabase/ssr"; import { drizzle } from "drizzle-orm/node-postgres"; import type { Fact } from "src/replicache"; import type { Attribute } from "src/replicache/attributes"; import { Database } from "supabase/database.types"; import { v7 } from "uuid"; import { entities, permission_tokens, permission_token_rights, entity_sets, facts, } from "drizzle/schema"; import { sql } from "drizzle-orm"; import { redirect } from "next/navigation"; import { cookies } from "next/headers"; import { pool } from "supabase/pool"; let supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, process.env.SUPABASE_SERVICE_ROLE_KEY as string, { cookies: {} }, ); export async function createNewLeafletFromTemplate( template_id: string, redirectUser?: boolean, ) { let auth_token = (await cookies()).get("auth_token")?.value; let res = await supabase .from("permission_tokens") .select("*, permission_token_rights(*)") .eq("id", template_id) .single(); let rootEntity = res.data?.root_entity; if (!rootEntity || !res.data) return { error: "Leaflet not found" } as const; let { data } = await supabase.rpc("get_facts", { root: rootEntity, }); let initialFacts = (data as unknown as Fact[]) || []; let oldEntityIDToNewID = {} as { [k: string]: string }; let oldEntities = initialFacts.reduce((acc, f) => { if (!acc.includes(f.entity)) acc.push(f.entity); return acc; }, [] as string[]); let newEntities = [] as string[]; for (let oldEntity of oldEntities) { let newEntity = v7(); oldEntityIDToNewID[oldEntity] = newEntity; newEntities.push(newEntity); } let newFacts = await Promise.all( initialFacts.map(async (fact) => { let entity = oldEntityIDToNewID[fact.entity]; let data = fact.data; if ( data.type === "ordered-reference" || data.type == "spatial-reference" || data.type === "reference" ) { data.value = oldEntityIDToNewID[data.value]; } if (data.type === "image") { let url = data.src.split("?"); let paths = url[0].split("/"); let newID = v7(); await supabase.storage .from("minilink-user-assets") .copy(paths[paths.length - 1], newID); let newPath = [...paths]; newPath[newPath.length - 1] = newID; let newURL = newPath.join("/"); if (url[1]) newURL += `?${url[1]}`; data.src = newURL; } return { entity, attribute: fact.attribute, data }; }), ); const client = await pool.connect(); const db = drizzle(client); let { permissionToken } = await db.transaction(async (tx) => { // Create a new entity set let [entity_set] = await tx.insert(entity_sets).values({}).returning(); await tx .insert(entities) .values(newEntities.map((e) => ({ id: e, set: entity_set.id }))); await tx.insert(facts).values( newFacts.map((f) => ({ id: v7(), entity: f.entity, attribute: f.attribute, data: sql`${f.data}`, })), ); let [permissionToken] = await tx .insert(permission_tokens) .values({ root_entity: oldEntityIDToNewID[rootEntity] }) .returning(); //and give it all the permission on that entity set let [rights] = await tx .insert(permission_token_rights) .values({ token: permissionToken.id, entity_set: entity_set.id, read: true, write: true, create_token: true, change_entity_set: true, }) .returning(); if (auth_token) { await tx.execute(sql` WITH auth_token AS ( SELECT identities.id as identity_id FROM email_auth_tokens LEFT JOIN identities ON email_auth_tokens.identity = identities.id WHERE email_auth_tokens.id = ${auth_token} AND email_auth_tokens.confirmed = true AND identities.id IS NOT NULL ) INSERT INTO permission_token_on_homepage (token, identity) SELECT ${permissionToken.id}, identity_id FROM auth_token `); } return { permissionToken, rights, entity_set }; }); client.release(); if (redirectUser) redirect(`/${permissionToken.id}`); return { id: permissionToken.id, error: null } as const; }