Sposta le route di notifiche push su PocketBase
Le route server in src/routes/api/public/ (promemoria-palloni, sollecita-presenze, apri-sondaggio, push-subscribe, notifiche-attive) usano pbAdmin al posto di supabaseAdmin per leggere/scrivere push_subscriptions e i dati necessari a comporre gli avvisi. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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<RigaIscrizione>();
|
||||
|
||||
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 });
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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 ?? []) });
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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<RigaTurno>();
|
||||
const salvati: Record<string, string> = {};
|
||||
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<RigaIscrizione>({ 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 });
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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(
|
||||
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_id: parsed.data.giocatoreId,
|
||||
giocatore: parsed.data.giocatoreId,
|
||||
p256dh: parsed.data.p256dh,
|
||||
auth: parsed.data.auth,
|
||||
},
|
||||
{ onConflict: "endpoint" },
|
||||
admin,
|
||||
);
|
||||
if (error) {
|
||||
} 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 });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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<RigaPresenza>({
|
||||
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<RigaIscrizione>({ 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user