fcm
This commit is contained in:
116
supabase/functions/send-reminders/index.ts
Normal file
116
supabase/functions/send-reminders/index.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"
|
||||
import { createClient } from "https://esm.sh/@supabase/supabase-js@2"
|
||||
import { JWT } from "https://esm.sh/google-auth-library@8.9.0"
|
||||
|
||||
const corsHeaders = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'authorization, x-client-info, apiKey, content-type',
|
||||
}
|
||||
|
||||
serve(async (req) => {
|
||||
// Gestione CORS per sicurezza
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response('ok', { headers: corsHeaders })
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. Inizializziamo il client Supabase con i poteri di Service Role (per scavalcare le RLS)
|
||||
const supabaseClient = createClient(
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? ''
|
||||
)
|
||||
|
||||
// 2. Recuperiamo la chiave di Firebase dai Secrets
|
||||
const firebaseSecret = Deno.env.get('FIREBASE_SERVICE_ACCOUNT')
|
||||
if (!firebaseSecret) throw new Error('Missing FIREBASE_SERVICE_ACCOUNT secret')
|
||||
const credentials = JSON.parse(firebaseSecret)
|
||||
|
||||
// 3. Prepariamo l'autenticazione OAuth2 per Firebase HTTP v1
|
||||
const jwtClient = new JWT({
|
||||
email: credentials.client_email,
|
||||
key: credentials.private_key,
|
||||
scopes: ['https://www.googleapis.com/auth/firebase.messaging'],
|
||||
})
|
||||
const tokens = await jwtClient.getAccessToken()
|
||||
const fcmAccessToken = tokens.token
|
||||
|
||||
// 4. Selezioniamo i reminder da inviare (trigger_at passato e non ancora inviati)
|
||||
const { data: reminders, error: fetchError } = await supabaseClient
|
||||
.from('task_reminders')
|
||||
.select('id, task_id, staff_id, channel, tasks(title, description)')
|
||||
.eq('channel', 'push')
|
||||
.eq('is_sent', false)
|
||||
.lte('trigger_at', new Date().toISOString())
|
||||
|
||||
if (fetchError) throw fetchError
|
||||
|
||||
if (!reminders || reminders.length === 0) {
|
||||
return new Response(JSON.stringify({ message: 'Nessun promemoria push da inviare.' }), {
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
status: 200,
|
||||
})
|
||||
}
|
||||
|
||||
// 5. Ciclo sui promemoria per raccogliere i token ed inviare
|
||||
for (const reminder of reminders) {
|
||||
const taskTitle = reminder.tasks?.title || 'Nuovo Task!';
|
||||
const taskBody = reminder.tasks?.description || 'Hai un task da completare.';
|
||||
|
||||
// Preleviamo tutti i dispositivi registrati per questo specifico membro dello staff
|
||||
const { data: devices } = await supabaseClient
|
||||
.from('staff_devices')
|
||||
.select('fcm_token')
|
||||
.eq('staff_id', reminder.staff_id)
|
||||
|
||||
if (devices && devices.length > 0) {
|
||||
// Spediamo la notifica a OGNI dispositivo associato all'utente
|
||||
for (const device of devices) {
|
||||
try {
|
||||
await fetch(
|
||||
`https://fcm.googleapis.com/v1/projects/${credentials.project_id}/messages:send`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${fcmAccessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
message: {
|
||||
token: device.fcm_token,
|
||||
notification: {
|
||||
title: taskTitle,
|
||||
body: taskBody,
|
||||
},
|
||||
data: {
|
||||
click_action: 'FLUTTER_NOTIFICATION_CLICK',
|
||||
taskId: reminder.task_id, // Fondamentale per far scattare il Deep Link all'apertura!
|
||||
},
|
||||
},
|
||||
}),
|
||||
}
|
||||
)
|
||||
} catch (pushErr) {
|
||||
console.error(`Errore invio push al token ${device.fcm_token}:`, pushErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Segnamo il reminder come inviato per non riprocessarlo al prossimo giro
|
||||
await supabaseClient
|
||||
.from('task_reminders')
|
||||
.update({ is_sent: true, updated_at: new Date().toISOString() })
|
||||
.eq('id', reminder.id)
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ success: true, processed: reminders.length }), {
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
status: 200,
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
return new Response(JSON.stringify({ error: error.message }), {
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
status: 500,
|
||||
})
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user