147 lines
5.0 KiB
JavaScript
147 lines
5.0 KiB
JavaScript
// ============================================================
|
|
// MVA Global Fret — Cloudflare Worker : Proxy HubSpot
|
|
// ============================================================
|
|
// Ce Worker contourne le CORS en faisant l'appel HubSpot
|
|
// côté serveur (Cloudflare), puis renvoie le résultat
|
|
// au navigateur avec les bons en-têtes CORS.
|
|
//
|
|
// DÉPLOIEMENT (gratuit, sans CLI) :
|
|
// 1. Aller sur https://dash.cloudflare.com/ → Workers & Pages
|
|
// 2. Créer un Worker → coller ce code → Enregistrer et déployer
|
|
// 3. Copier l'URL du Worker (ex: https://mva-proxy.xxx.workers.dev)
|
|
// 4. Coller cette URL dans js/form-handler.js à la constante WORKER_PROXY_URL
|
|
//
|
|
// SÉCURITÉ :
|
|
// - Stocker le token dans une variable d'environnement Cloudflare :
|
|
// Workers & Pages → Votre Worker → Paramètres → Variables et secrets
|
|
// Nom : HUBSPOT_TOKEN Valeur : pat-eu1-e3c92146-bb17-45fe-8d77-0c665fc4df3b
|
|
// - Ce token est en lecture seule (crm.objects.contacts.read uniquement)
|
|
// ============================================================
|
|
|
|
export default {
|
|
async fetch(request, env) {
|
|
|
|
// En-têtes CORS autorisés
|
|
const corsHeaders = {
|
|
'Access-Control-Allow-Origin': '*',
|
|
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
'Access-Control-Allow-Headers': 'Content-Type',
|
|
};
|
|
|
|
// Réponse au preflight CORS (OPTIONS)
|
|
if (request.method === 'OPTIONS') {
|
|
return new Response(null, { headers: corsHeaders });
|
|
}
|
|
|
|
// Seule la méthode POST est acceptée
|
|
if (request.method !== 'POST') {
|
|
return new Response('Method Not Allowed', { status: 405 });
|
|
}
|
|
|
|
// Lecture du token (variable d'env Cloudflare ou fallback hardcodé)
|
|
const token = (env && env.HUBSPOT_TOKEN)
|
|
? env.HUBSPOT_TOKEN
|
|
: 'pat-eu1-e3c92146-bb17-45fe-8d77-0c665fc4df3b';
|
|
|
|
try {
|
|
const body = await request.json();
|
|
const { email, action } = body;
|
|
|
|
// ── ACTION : prochain numéro de référence séquentiel ──────────────────
|
|
if (action === 'nextRef') {
|
|
const hsResponse = await fetch(
|
|
'https://api.hubapi.com/crm/v3/objects/contacts/search',
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${token}`,
|
|
},
|
|
body: JSON.stringify({
|
|
filterGroups: [{
|
|
filters: [{
|
|
propertyName: 'reference_client',
|
|
operator: 'HAS_PROPERTY',
|
|
value: '',
|
|
}]
|
|
}],
|
|
properties: ['reference_client'],
|
|
limit: 100,
|
|
}),
|
|
}
|
|
);
|
|
|
|
const data = await hsResponse.json();
|
|
let maxNum = 0;
|
|
|
|
if (data.results) {
|
|
data.results.forEach(contact => {
|
|
const ref = contact.properties?.reference_client || '';
|
|
const match = ref.match(/^MVA-(\d+)$/);
|
|
if (match) {
|
|
const num = parseInt(match[1], 10);
|
|
if (num > maxNum) maxNum = num;
|
|
}
|
|
});
|
|
}
|
|
|
|
const nextNum = maxNum + 1;
|
|
const nextRef = 'MVA-' + String(nextNum).padStart(3, '0');
|
|
|
|
return new Response(JSON.stringify({ nextRef }), {
|
|
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
|
});
|
|
}
|
|
|
|
// ── ACTION : vérification doublon par email (défaut) ──────────────────
|
|
if (!email || typeof email !== 'string') {
|
|
return new Response(
|
|
JSON.stringify({ error: 'Email requis' }),
|
|
{ status: 400, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
);
|
|
}
|
|
|
|
// Appel HubSpot CRM (pas de CORS côté Worker)
|
|
const hsResponse = await fetch(
|
|
'https://api.hubapi.com/crm/v3/objects/contacts/search',
|
|
{
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Authorization': `Bearer ${token}`,
|
|
},
|
|
body: JSON.stringify({
|
|
filterGroups: [{
|
|
filters: [{
|
|
propertyName: 'email',
|
|
operator: 'EQ',
|
|
value: email.toLowerCase().trim(),
|
|
}]
|
|
}],
|
|
properties: ['firstname', 'lastname', 'email', 'reference_client'],
|
|
}),
|
|
}
|
|
);
|
|
|
|
if (!hsResponse.ok) {
|
|
return new Response(
|
|
JSON.stringify({ error: `HubSpot error: ${hsResponse.status}` }),
|
|
{ status: 502, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
);
|
|
}
|
|
|
|
const data = await hsResponse.json();
|
|
|
|
return new Response(JSON.stringify(data), {
|
|
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
|
});
|
|
|
|
} catch (err) {
|
|
return new Response(
|
|
JSON.stringify({ error: err.message }),
|
|
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
);
|
|
}
|
|
},
|
|
};
|