123 lines
4.0 KiB
TypeScript
123 lines
4.0 KiB
TypeScript
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"
|
|
import { createClient } from "https://esm.sh/@supabase/supabase-js@2.7.1"
|
|
import { GoogleAuth } from "https://esm.sh/google-auth-library@8.7.0"
|
|
|
|
serve(async (req) => {
|
|
try {
|
|
const payload = await req.json()
|
|
console.log("Webhook Payload:", payload)
|
|
|
|
const record = payload.record
|
|
if (!record) throw new Error("No record found in payload")
|
|
|
|
const supabaseUrl = Deno.env.get("SUPABASE_URL")
|
|
const supabaseServiceKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")
|
|
if (!supabaseUrl || !supabaseServiceKey) throw new Error("Supabase credentials not set")
|
|
|
|
const supabase = createClient(supabaseUrl, supabaseServiceKey)
|
|
|
|
let muridId = record.id_murid
|
|
let namaUser = record.nama_user || "Siswa"
|
|
|
|
if (!muridId) {
|
|
if (record.rfid) {
|
|
const { data: muridData } = await supabase.from("murid").select("id_tabel").eq("rfid", record.rfid).single()
|
|
if (muridData) muridId = muridData.id_tabel
|
|
} else {
|
|
const { data: muridData } = await supabase.from("murid").select("id_tabel").eq("nama", namaUser).single()
|
|
if (muridData) muridId = muridData.id_tabel
|
|
}
|
|
}
|
|
|
|
let targetUserId = muridId;
|
|
|
|
if (!targetUserId && namaUser && namaUser !== "Siswa") {
|
|
const { data: guruData } = await supabase.from("guru").select("id_tabel").eq("name", namaUser).maybeSingle()
|
|
if (guruData) targetUserId = guruData.id_tabel
|
|
}
|
|
|
|
if (!targetUserId) {
|
|
return new Response(JSON.stringify({ message: "No target user to notify" }), {
|
|
headers: { "Content-Type": "application/json" },
|
|
status: 200,
|
|
})
|
|
}
|
|
|
|
const query = supabase.from("fcm_tokens").select("token").eq("user_id", targetUserId)
|
|
|
|
const { data: tokensData, error: tokenError } = await query
|
|
if (tokenError) throw tokenError
|
|
|
|
const tokens = tokensData.map(t => t.token)
|
|
if (tokens.length === 0) {
|
|
return new Response(JSON.stringify({ message: "No devices to notify" }), {
|
|
headers: { "Content-Type": "application/json" },
|
|
status: 200,
|
|
})
|
|
}
|
|
|
|
console.log(`Found ${tokens.length} tokens to notify.`)
|
|
|
|
const fcmServiceAccountStr = Deno.env.get("FIREBASE_SERVICE_ACCOUNT")
|
|
if (!fcmServiceAccountStr) throw new Error("FIREBASE_SERVICE_ACCOUNT secret is missing")
|
|
|
|
const serviceAccount = JSON.parse(fcmServiceAccountStr)
|
|
|
|
const auth = new GoogleAuth({
|
|
credentials: {
|
|
client_email: serviceAccount.client_email,
|
|
private_key: serviceAccount.private_key,
|
|
},
|
|
scopes: ["https://www.googleapis.com/auth/firebase.messaging"],
|
|
})
|
|
|
|
const accessToken = await auth.getAccessToken()
|
|
|
|
const message = {
|
|
message: {
|
|
notification: {
|
|
title: "Aplikasi Absensi",
|
|
body: `${namaUser} telah melakukan absensi.`
|
|
},
|
|
data: {
|
|
id_murid: muridId || "",
|
|
nama_user: namaUser,
|
|
id_tabel: record.id_tabel || "",
|
|
type: "absen"
|
|
}
|
|
}
|
|
}
|
|
|
|
const projectId = serviceAccount.project_id
|
|
const fcmUrl = `https://fcm.googleapis.com/v1/projects/${projectId}/messages:send`
|
|
|
|
const promises = tokens.map(async (token) => {
|
|
const msg = { ...message, message: { ...message.message, token: token } }
|
|
const res = await fetch(fcmUrl, {
|
|
method: "POST",
|
|
headers: {
|
|
"Authorization": `Bearer ${accessToken}`,
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(msg),
|
|
})
|
|
if (!res.ok) {
|
|
console.error(`Failed to send to ${token}:`, await res.text())
|
|
}
|
|
})
|
|
|
|
await Promise.all(promises)
|
|
|
|
return new Response(JSON.stringify({ success: true, notified: tokens.length }), {
|
|
headers: { "Content-Type": "application/json" },
|
|
status: 200,
|
|
})
|
|
} catch (error) {
|
|
console.error("Error:", error)
|
|
return new Response(JSON.stringify({ error: error.message }), {
|
|
headers: { "Content-Type": "application/json" },
|
|
status: 500,
|
|
})
|
|
}
|
|
})
|