diff --git a/src/routes/api/public/apri-sondaggio.ts b/src/routes/api/public/apri-sondaggio.ts index 0ea2b89..f30d45b 100644 --- a/src/routes/api/public/apri-sondaggio.ts +++ b/src/routes/api/public/apri-sondaggio.ts @@ -6,6 +6,8 @@ import { inviaPush } from "@/lib/webpush.server"; const schema = z.object({ eventoId: z.string().min(1).max(50) }); +type RigaIscrizione = { id: string; endpoint: string; p256dh: string; auth: string }; + /** Avviso "sondaggio pre-partita aperto": lo fa partire un admin dalla pagina partita. */ export const Route = createFileRoute("/api/public/apri-sondaggio")({ server: { @@ -21,23 +23,21 @@ export const Route = createFileRoute("/api/public/apri-sondaggio")({ const partita = eventi.find((e) => e.id === parsed.data.eventoId); if (!partita) return new Response("Evento non trovato", { status: 404 }); - const { supabaseAdmin } = await import("@/integrations/supabase/client.server"); - const { data: iscrizioni } = await supabaseAdmin - .from("push_subscriptions") - .select("endpoint, p256dh, auth"); + const { pbAdmin } = await import("@/integrations/pocketbase/client.server"); + const admin = await pbAdmin(); + const iscrizioni = await admin + .collection("push_subscriptions") + .getFullList(); const titolo = "💩 Sondaggio pre-partita aperto"; const testo = `${partita.titolo} · ore ${partita.ora}. Quante cacche hai fatto? Rispondi prima del fischio d'inizio.`; let inviate = 0; - for (const iscrizione of iscrizioni ?? []) { + for (const iscrizione of iscrizioni) { try { const { stato } = await inviaPush(iscrizione, titolo, testo); if (stato === 404 || stato === 410) { - await supabaseAdmin - .from("push_subscriptions") - .delete() - .eq("endpoint", iscrizione.endpoint); + await admin.collection("push_subscriptions").delete(iscrizione.id); } else if (stato >= 200 && stato < 300) { inviate += 1; } @@ -46,7 +46,7 @@ export const Route = createFileRoute("/api/public/apri-sondaggio")({ } } - return Response.json({ inviate, destinatari: (iscrizioni ?? []).length }); + return Response.json({ inviate, destinatari: iscrizioni.length }); }, }, }, diff --git a/src/routes/api/public/notifiche-attive.ts b/src/routes/api/public/notifiche-attive.ts index 092044d..d6387d3 100644 --- a/src/routes/api/public/notifiche-attive.ts +++ b/src/routes/api/public/notifiche-attive.ts @@ -9,16 +9,20 @@ export const Route = createFileRoute("/api/public/notifiche-attive")({ const negato = await richiediAdmin(request); if (negato) return negato; - const { supabaseAdmin } = await import("@/integrations/supabase/client.server"); - const { data, error } = await supabaseAdmin - .from("push_subscriptions") - .select("giocatore_id"); - if (error) { + const { pbAdmin } = await import("@/integrations/pocketbase/client.server"); + const admin = await pbAdmin(); + + try { + const righe = await admin + .collection("push_subscriptions") + .getFullList<{ giocatore: string }>(); + return Response.json({ + giocatoreIds: idsConNotificheAttive(righe.map((r) => ({ giocatore_id: r.giocatore }))), + }); + } catch (error) { console.error("notifiche-attive", error); return new Response("Errore lettura", { status: 500 }); } - - return Response.json({ giocatoreIds: idsConNotificheAttive(data ?? []) }); }, }, }, diff --git a/src/routes/api/public/promemoria-palloni.ts b/src/routes/api/public/promemoria-palloni.ts index 97a318c..73c33b9 100644 --- a/src/routes/api/public/promemoria-palloni.ts +++ b/src/routes/api/public/promemoria-palloni.ts @@ -9,6 +9,15 @@ import { leggiEventi } from "@/lib/eventi.server"; const schema = z.object({ eventoId: z.string().min(1).max(50) }); +type RigaTurno = { evento: string; giocatore: string }; +type RigaIscrizione = { + id: string; + endpoint: string; + giocatore: string; + p256dh: string; + auth: string; +}; + /** * Promemoria del turno palloni per un evento: lo fa partire un admin dalla pagina * dell'evento (DD-025). Il testo viaggia cifrato dentro la push. @@ -27,13 +36,12 @@ export const Route = createFileRoute("/api/public/promemoria-palloni")({ const evento = eventi.find((e) => e.id === parsed.data.eventoId); if (!evento) return new Response("Evento non trovato", { status: 404 }); - const { supabaseAdmin } = await import("@/integrations/supabase/client.server"); + const { pbAdmin } = await import("@/integrations/pocketbase/client.server"); + const admin = await pbAdmin(); - const { data: righe } = await supabaseAdmin - .from("turni_palloni") - .select("evento_id, giocatore_id"); + const righeTurni = await admin.collection("turni_palloni").getFullList(); const salvati: Record = {}; - for (const riga of righe ?? []) salvati[riga.evento_id] = riga.giocatore_id; + for (const riga of righeTurni) salvati[riga.evento] = riga.giocatore; const squadra = await leggiGiocatoriSquadra(); const rosa = squadra @@ -44,25 +52,21 @@ export const Route = createFileRoute("/api/public/promemoria-palloni")({ const avvisi = avvisiPalloniEvento(turni, eventi, evento.id); if (avvisi.length === 0) return Response.json({ inviate: 0, destinatari: 0 }); - const { data: iscrizioni } = await supabaseAdmin - .from("push_subscriptions") - .select("endpoint, giocatore_id, p256dh, auth") - .in( - "giocatore_id", - avvisi.map((a) => a.giocatoreId), - ); + const idsFiltro = avvisi.map((a) => a.giocatoreId); + const filtro = idsFiltro.map((_, i) => `giocatore = {:g${i}}`).join(" || "); + const parametri = Object.fromEntries(idsFiltro.map((id, i) => [`g${i}`, id])); + const iscrizioni = await admin + .collection("push_subscriptions") + .getFullList({ filter: admin.filter(filtro, parametri) }); let inviate = 0; - for (const iscrizione of iscrizioni ?? []) { - const avviso = avvisi.find((a) => a.giocatoreId === iscrizione.giocatore_id); + for (const iscrizione of iscrizioni) { + const avviso = avvisi.find((a) => a.giocatoreId === iscrizione.giocatore); if (!avviso) continue; try { const { stato } = await inviaPush(iscrizione, avviso.titolo, avviso.testo); if (stato === 404 || stato === 410) { - await supabaseAdmin - .from("push_subscriptions") - .delete() - .eq("endpoint", iscrizione.endpoint); + await admin.collection("push_subscriptions").delete(iscrizione.id); } else if (stato >= 200 && stato < 300) { inviate += 1; } @@ -71,7 +75,7 @@ export const Route = createFileRoute("/api/public/promemoria-palloni")({ } } - return Response.json({ inviate, destinatari: (iscrizioni ?? []).length }); + return Response.json({ inviate, destinatari: iscrizioni.length }); }, }, }, diff --git a/src/routes/api/public/push-subscribe.ts b/src/routes/api/public/push-subscribe.ts index b413fe0..1507d41 100644 --- a/src/routes/api/public/push-subscribe.ts +++ b/src/routes/api/public/push-subscribe.ts @@ -17,17 +17,24 @@ export const Route = createFileRoute("/api/public/push-subscribe")({ const parsed = schemaIscrizione.safeParse(await request.json()); if (!parsed.success) return new Response("Dati non validi", { status: 400 }); - const { supabaseAdmin } = await import("@/integrations/supabase/client.server"); - const { error } = await supabaseAdmin.from("push_subscriptions").upsert( - { - endpoint: parsed.data.endpoint, - giocatore_id: parsed.data.giocatoreId, - p256dh: parsed.data.p256dh, - auth: parsed.data.auth, - }, - { onConflict: "endpoint" }, - ); - if (error) { + const { pbAdmin } = await import("@/integrations/pocketbase/client.server"); + const { upsertByFilter } = await import("@/integrations/pocketbase/upsert"); + const admin = await pbAdmin(); + + try { + await upsertByFilter( + "push_subscriptions", + "endpoint = {:endpoint}", + { endpoint: parsed.data.endpoint }, + { + endpoint: parsed.data.endpoint, + giocatore: parsed.data.giocatoreId, + p256dh: parsed.data.p256dh, + auth: parsed.data.auth, + }, + admin, + ); + } catch (error) { console.error("push-subscribe", error); return new Response("Errore salvataggio", { status: 500 }); } @@ -37,11 +44,15 @@ export const Route = createFileRoute("/api/public/push-subscribe")({ const parsed = schemaCancellazione.safeParse(await request.json()); if (!parsed.success) return new Response("Dati non validi", { status: 400 }); - const { supabaseAdmin } = await import("@/integrations/supabase/client.server"); - await supabaseAdmin - .from("push_subscriptions") - .delete() - .eq("endpoint", parsed.data.endpoint); + const { pbAdmin } = await import("@/integrations/pocketbase/client.server"); + const admin = await pbAdmin(); + const esistente = await admin + .collection("push_subscriptions") + .getFirstListItem( + admin.filter("endpoint = {:endpoint}", { endpoint: parsed.data.endpoint }), + ) + .catch(() => null); + if (esistente) await admin.collection("push_subscriptions").delete(esistente.id); return Response.json({ ok: true }); }, }, diff --git a/src/routes/api/public/sollecita-presenze.ts b/src/routes/api/public/sollecita-presenze.ts index e2864cc..94c37e5 100644 --- a/src/routes/api/public/sollecita-presenze.ts +++ b/src/routes/api/public/sollecita-presenze.ts @@ -12,6 +12,9 @@ const schema = z.object({ da: z.string().min(1).max(60).optional(), }); +type RigaPresenza = { giocatore: string; stato: string }; +type RigaIscrizione = { id: string; endpoint: string; p256dh: string; auth: string }; + export const Route = createFileRoute("/api/public/sollecita-presenze")({ server: { handlers: { @@ -26,22 +29,26 @@ export const Route = createFileRoute("/api/public/sollecita-presenze")({ const evento = eventi.find((e) => e.id === parsed.data.eventoId); if (!evento) return new Response("Evento non trovato", { status: 404 }); - const { supabaseAdmin } = await import("@/integrations/supabase/client.server"); + const { pbAdmin } = await import("@/integrations/pocketbase/client.server"); + const admin = await pbAdmin(); - const { data: righe } = await supabaseAdmin - .from("risposte_presenze") - .select("giocatore_id, stato") - .eq("evento_id", evento.id); + const righe = await admin.collection("risposte_presenze").getFullList({ + filter: admin.filter("evento = {:evento}", { evento: evento.id }), + }); const squadra = await leggiGiocatoriSquadra(); - const destinatari = destinatariSollecito(squadra, righe ?? []); + const destinatari = destinatariSollecito( + squadra, + righe.map((r) => ({ giocatore_id: r.giocatore, stato: r.stato })), + ); if (destinatari.length === 0) return Response.json({ inviate: 0, destinatari: 0 }); - const { data: iscrizioni } = await supabaseAdmin - .from("push_subscriptions") - .select("endpoint, p256dh, auth") - .in("giocatore_id", destinatari); + const filtro = destinatari.map((_, i) => `giocatore = {:g${i}}`).join(" || "); + const parametri = Object.fromEntries(destinatari.map((id, i) => [`g${i}`, id])); + const iscrizioni = await admin + .collection("push_subscriptions") + .getFullList({ filter: admin.filter(filtro, parametri) }); const titolo = "Manca la tua risposta"; const testo = `${evento.titolo} · ${formatData(evento.data)} ore ${evento.ora}. ${ @@ -49,14 +56,11 @@ export const Route = createFileRoute("/api/public/sollecita-presenze")({ } una conferma: presente, assente o in ritardo?`; let inviate = 0; - for (const iscrizione of iscrizioni ?? []) { + for (const iscrizione of iscrizioni) { try { const { stato } = await inviaPush(iscrizione, titolo, testo); if (stato === 404 || stato === 410) { - await supabaseAdmin - .from("push_subscriptions") - .delete() - .eq("endpoint", iscrizione.endpoint); + await admin.collection("push_subscriptions").delete(iscrizione.id); } else if (stato >= 200 && stato < 300) { inviate += 1; }