#!/usr/bin/env node /** * Script de migration pour générer les slugs et short_ids pour les données existantes * * Usage: node scripts/migrate-short-links.js */ const { createClient } = require('@supabase/supabase-js'); require('dotenv').config({ path: '.env.local' }); const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY; if (!supabaseUrl || !supabaseServiceKey) { console.error('❌ Variables d\'environnement manquantes'); console.error('NEXT_PUBLIC_SUPABASE_URL et SUPABASE_SERVICE_ROLE_KEY sont requis'); process.exit(1); } const supabase = createClient(supabaseUrl, supabaseServiceKey); async function generateSlug(title) { // Convertir en minuscules et remplacer les caractères spéciaux let slug = title.toLowerCase() .replace(/[^a-z0-9\s]/g, '') .replace(/\s+/g, '-') .trim(); // Si le slug est vide, utiliser 'campagne' if (!slug) { slug = 'campagne'; } // Vérifier si le slug existe déjà et ajouter un numéro si nécessaire let counter = 0; let finalSlug = slug; while (true) { const { data, error } = await supabase .from('campaigns') .select('id') .eq('slug', finalSlug) .single(); if (error && error.code === 'PGRST116') { // Aucune campagne trouvée avec ce slug, on peut l'utiliser break; } if (error) { throw error; } // Le slug existe déjà, ajouter un numéro counter++; finalSlug = `${slug}-${counter}`; } return finalSlug; } async function generateShortId() { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; let counter = 0; while (counter < 100) { // Générer un identifiant de 6 caractères let result = ''; for (let i = 0; i < 6; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } // Vérifier si le short_id existe déjà const { data, error } = await supabase .from('participants') .select('id') .eq('short_id', result) .single(); if (error && error.code === 'PGRST116') { // Aucun participant trouvé avec ce short_id, on peut l'utiliser return result; } if (error) { throw error; } counter++; } throw new Error('Impossible de générer un short_id unique après 100 tentatives'); } async function migrateCampaigns() { console.log('🔄 Migration des campagnes...'); // Récupérer toutes les campagnes sans slug const { data: campaigns, error } = await supabase .from('campaigns') .select('id, title') .is('slug', null); if (error) { console.error('❌ Erreur lors de la récupération des campagnes:', error); return; } console.log(`📋 ${campaigns.length} campagnes à migrer`); for (const campaign of campaigns) { try { const slug = await generateSlug(campaign.title); const { error: updateError } = await supabase .from('campaigns') .update({ slug }) .eq('id', campaign.id); if (updateError) { console.error(`❌ Erreur lors de la mise à jour de la campagne ${campaign.id}:`, updateError); } else { console.log(`✅ Campagne "${campaign.title}" -> slug: ${slug}`); } } catch (error) { console.error(`❌ Erreur lors de la génération du slug pour "${campaign.title}":`, error); } } console.log('✅ Migration des campagnes terminée'); } async function migrateParticipants() { console.log('🔄 Migration des participants...'); // Récupérer tous les participants sans short_id const { data: participants, error } = await supabase .from('participants') .select('id, first_name, last_name') .is('short_id', null); if (error) { console.error('❌ Erreur lors de la récupération des participants:', error); return; } console.log(`📋 ${participants.length} participants à migrer`); for (const participant of participants) { try { const shortId = await generateShortId(); const { error: updateError } = await supabase .from('participants') .update({ short_id: shortId }) .eq('id', participant.id); if (updateError) { console.error(`❌ Erreur lors de la mise à jour du participant ${participant.id}:`, updateError); } else { console.log(`✅ Participant "${participant.first_name} ${participant.last_name}" -> short_id: ${shortId}`); } } catch (error) { console.error(`❌ Erreur lors de la génération du short_id pour "${participant.first_name} ${participant.last_name}":`, error); } } console.log('✅ Migration des participants terminée'); } async function main() { console.log('🚀 Début de la migration des liens courts...\n'); try { await migrateCampaigns(); console.log(''); await migrateParticipants(); console.log('\n🎉 Migration terminée avec succès !'); console.log('\n📝 Résumé des nouvelles routes :'); console.log('- Dépôt de propositions : /p/[slug]'); console.log('- Vote : /v/[shortId]'); console.log('- Les anciennes routes restent fonctionnelles pour la compatibilité'); } catch (error) { console.error('❌ Erreur lors de la migration:', error); process.exit(1); } } if (require.main === module) { main(); } module.exports = { migrateCampaigns, migrateParticipants };