import type { APIRoute } from 'astro' export const prerender = false const KIT_API_BASE = 'https://api.kit.com/v4' const TAG_NAME = 'AEP - sans perso' function htmlPage(title: string, heading: string, message: string): string { return ` ${title} — trans-former.fr

${heading}

${message}

← Retour sur trans-former.fr
` } async function getSubscriberByEmail(email: string, apiKey: string): Promise { const url = `${KIT_API_BASE}/subscribers?email_address=${encodeURIComponent(email)}` const res = await fetch(url, { headers: { 'X-Kit-Api-Key': apiKey }, signal: AbortSignal.timeout(10000), }) if (!res.ok) return null const data = await res.json() if (!data?.subscribers?.length) return null return String(data.subscribers[0].id) } async function getTagId(apiKey: string): Promise { const url = `${KIT_API_BASE}/tags` const res = await fetch(url, { headers: { 'X-Kit-Api-Key': apiKey }, signal: AbortSignal.timeout(10000), }) if (!res.ok) return null const data = await res.json() const tag = data?.tags?.find((t: any) => t.name === TAG_NAME) return tag?.id ?? null } async function tagSubscriber(subscriberId: string, tagId: number, apiKey: string): Promise { const url = `${KIT_API_BASE}/tags/${tagId}/subscribers` const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Kit-Api-Key': apiKey, }, body: JSON.stringify({ id: subscriberId }), signal: AbortSignal.timeout(10000), }) return res.ok || res.status === 409 } async function untagSubscriber(subscriberId: string, tagId: number, apiKey: string): Promise { const url = `${KIT_API_BASE}/tags/${tagId}/subscribers/${subscriberId}` const res = await fetch(url, { method: 'DELETE', headers: { 'X-Kit-Api-Key': apiKey }, signal: AbortSignal.timeout(10000), }) return res.ok || res.status === 404 } export const GET: APIRoute = async ({ url }) => { const KIT_API_KEY = import.meta.env.KIT_API_SECRET_V4 if (!KIT_API_KEY) { return new Response(htmlPage( 'Erreur', 'Configuration manquante', 'Le service de désinscription n\'est pas configuré. Contacte-moi à julesneny8@gmail.com.' ), { status: 500, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } const email = (url.searchParams.get('email') || '').trim().toLowerCase() const action = url.searchParams.get('action') if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { return new Response(htmlPage( 'Lien invalide', 'Lien invalide', 'Le lien que tu as suivi est incomplet ou mal formé. Essaye de copier-coller l\'URL complète depuis l\'email.' ), { status: 400, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } if (action !== 'unsubscribe' && action !== 'resubscribe') { return new Response(htmlPage( 'Action inconnue', 'Action inconnue', 'Le lien que tu as suivi ne correspond à aucune action connue.' ), { status: 400, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } try { const subscriberId = await getSubscriberByEmail(email, KIT_API_KEY) if (!subscriberId) { return new Response(htmlPage( 'Email inconnu', 'Email inconnu', 'Cet email n\'est pas abonné à la newsletter. Si tu penses qu\'il s\'agit d\'une erreur, écris-moi à julesneny8@gmail.com.' ), { status: 404, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } const tagId = await getTagId(KIT_API_KEY) if (!tagId) { return new Response(htmlPage( 'Erreur', 'Configuration manquante', 'Le tag de désinscription est introuvable. Contacte-moi à julesneny8@gmail.com.' ), { status: 500, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } if (action === 'unsubscribe') { const result = await tagSubscriber(subscriberId, tagId, KIT_API_KEY) if (!result) { return new Response(htmlPage( 'Erreur', 'Erreur technique', 'Une erreur est survenue lors de la désinscription. Réessaie ou écris-moi à julesneny8@gmail.com.' ), { status: 500, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } return new Response(htmlPage( 'Désinscription réussie', 'Tu es désinscrit·e', 'Tu ne recevras plus les lettres « perso » de l\'infolettre Architecture d\'Écologie Politique. Tu continues à recevoir les textes de fond.

Si tu changes d\'avis, un lien de réabonnement est disponible dans chaque email de fond.' ), { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } if (action === 'resubscribe') { const result = await untagSubscriber(subscriberId, tagId, KIT_API_KEY) if (!result) { return new Response(htmlPage( 'Erreur', 'Erreur technique', 'Une erreur est survenue lors du réabonnement. Réessaie ou écris-moi à julesneny8@gmail.com.' ), { status: 500, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } return new Response(htmlPage( 'Réabonnement réussi', 'Tu es de nouveau abonné·e', 'Tu recevras à nouveau les lettres « perso » de l\'infolettre Architecture d\'Écologie Politique. Merci de ton intérêt !' ), { status: 200, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } return new Response(null, { status: 400 }) } catch (e) { return new Response(htmlPage( 'Erreur', 'Erreur technique', 'Une erreur inattendue est survenue. Réessaie ou écris-moi à julesneny8@gmail.com.' ), { status: 500, headers: { 'Content-Type': 'text/html; charset=utf-8' }, }) } }