// server.js const express = require('express'); const axios = require('axios'); const path = require('path'); const app = express(); const port = process.env.PORT || 3000; // Servir les fichiers statiques app.use(express.static('public')); // Route pour vérifier que le serveur fonctionne app.get('/api/health', (req, res) => { res.json({ status: 'ok', time: new Date().toISOString() }); }); // Route principale pour extraire les données d'une campagne Ulule app.get('/api/ulule/:slug', async (req, res) => { try { const { slug } = req.params; console.log(`Récupération des données pour la campagne: ${slug}`); // Utiliser directement l'API publique d'Ulule const apiUrl = `https://api.ulule.com/v1/projects/${slug}`; console.log(`Tentative d'accès à l'API: ${apiUrl}`); const response = await axios.get(apiUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Accept': 'application/json', 'Cache-Control': 'no-cache' }, timeout: 10000 }); // Vérifier si la réponse est valide if (response.status === 200 && response.data) { console.log("Données récupérées avec succès depuis l'API d'Ulule"); const projectData = response.data; // Formater les données pour notre application const formattedData = { name: projectData.name ? (projectData.name.fr || projectData.name.en || Object.values(projectData.name)[0]) : slug, amount_raised: projectData.amount_raised || 0, goal: projectData.goal || 0, currency: projectData.currency || "EUR", supporters_count: projectData.supporters_count || 0, days_left: 0, percent: projectData.percent || 0, success: true, source: 'api' }; // Calculer les jours restants if (projectData.date_end) { const endDate = new Date(projectData.date_end); const now = new Date(); const diffTime = endDate - now; formattedData.days_left = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); } return res.json(formattedData); } else { throw new Error(`Réponse invalide de l'API: ${response.status}`); } } catch (error) { console.error('Erreur lors de la récupération des données:', error.message); // En cas d'erreur, renvoyer des données de démonstration res.json({ name: req.params.slug, amount_raised: 5000, goal: 10000, currency: "EUR", supporters_count: 42, days_left: 15, percent: 50, success: false, source: 'error', error: error.message, message: "Données de démonstration en raison d'une erreur" }); } }); // Route pour récupérer les détails des récompenses d'une campagne app.get('/api/ulule/:slug/rewards', async (req, res) => { try { const { slug } = req.params; console.log(`Récupération des récompenses pour la campagne: ${slug}`); // Utiliser l'API Ulule const apiUrl = `https://api.ulule.com/v1/projects/${slug}`; const response = await axios.get(apiUrl); if (response.status === 200 && response.data && response.data.rewards) { console.log(`${response.data.rewards.length} récompenses récupérées`); // Simplifier les données des récompenses const rewards = response.data.rewards.map(reward => ({ id: reward.id, title: reward.title ? (reward.title.fr || reward.title.en || Object.values(reward.title)[0]) : '', price: reward.price, description: reward.description ? (reward.description.fr || reward.description.en || Object.values(reward.description)[0]) : '', stock: reward.stock, stock_available: reward.stock_available, orders_count: reward.orders_count, date_delivery: reward.date_delivery })); return res.json({ rewards }); } else { throw new Error(`Aucune récompense trouvée pour la campagne ${slug}`); } } catch (error) { console.error('Erreur lors de la récupération des récompenses:', error.message); return res.json({ rewards: [] }); } }); // Route pour récupérer les contributeurs d'une campagne app.get('/api/ulule/:slug/supporters', async (req, res) => { try { const { slug } = req.params; console.log(`Récupération des contributeurs pour la campagne: ${slug}`); // Utiliser l'API Ulule pour récupérer les contributeurs avec des champs supplémentaires const apiUrl = `https://api.ulule.com/v1/projects/${slug}/supporters?extra_fields=latest_project_order,latest_project_comment`; console.log(`Tentative d'accès à l'API des supporters: ${apiUrl}`); const response = await axios.get(apiUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Accept': 'application/json', 'Cache-Control': 'no-cache' }, timeout: 10000 }); if (response.status === 200 && response.data && response.data.supporters) { console.log(`${response.data.supporters.length} contributeurs récupérés`); // Formater les données des contributeurs const contributors = response.data.supporters.map(supporter => { // Récupérer le nom complet ou le nom d'utilisateur let name = supporter.screenname || supporter.name || 'Contributeur anonyme'; // Extraire les informations de commande si disponibles let reward = ''; let reward_desc = ''; let amount = 0; let comment = ''; if (supporter.latest_project_order && supporter.latest_project_order.items && supporter.latest_project_order.items.length > 0) { // Récupérer la première récompense const firstItem = supporter.latest_project_order.items[0]; amount = firstItem.line_subtotal || firstItem.unit_price || 0; if (firstItem.reward.parent && firstItem.reward.parent.delivery) { if (firstItem.reward.parent.delivery.shipping_type == 'physical-delivery') { amount = firstItem.line_subtotal || firstItem.unit_price || 0; } } // Récupérer le titre de la récompense if (firstItem.reward && firstItem.reward.title) { const titles = firstItem.reward.title || firstItem.reward.parent.title; reward = titles.fr || Object.values(titles)[0] || ''; reward_desc = firstItem.reward.description_fr; reward = reward; } else if (firstItem.reward.parent && firstItem.reward.parent.title) { const titles = firstItem.reward.parent.title; reward = titles.fr || firstItem.reward.description_fr || Object.values(titles)[0] || ''; reward_desc = firstItem.reward.description_fr; reward = reward + ' - ' + reward_desc; } // Ajouter un pourboire si présent if (supporter.latest_project_order.tip && supporter.latest_project_order.tip > 0) { amount += supporter.latest_project_order.tip; } } // Récupérer le commentaire si disponible if (supporter.latest_project_comment && supporter.latest_project_comment.comment) { comment = supporter.latest_project_comment.comment; } return { id: supporter.id, name: name, reward: reward, amount: amount, avatar: supporter.avatar ? (supporter.avatar['90'] || '') : '', date_joined: supporter.date_joined, comment: comment, location: supporter.location || '' }; }); return res.json({ contributors }); } else { throw new Error(`Erreur lors de la récupération des contributeurs: ${response.status}`); } } catch (error) { console.error('Erreur lors de la récupération des contributeurs:', error.message); // En cas d'erreur, renvoyer des données de démonstration return res.json({ contributors: [ { name: "Contributeur 1", reward: "Pack Tour", amount: 40, avatar: "", comment: "Super projet!" }, { name: "Contributeur 2", reward: "Pack Cavalier", amount: 26, avatar: "", comment: "" }, { name: "Contributeur 3", reward: "Pack Roi", amount: 75, avatar: "", comment: "J'adore!" }, { name: "Contributeur 4", reward: "Pack Tour", amount: 40, avatar: "", comment: "" }, { name: "Contributeur 5", reward: "Pack Pion", amount: 6, avatar: "", comment: "" } ] }); } }); // Page d'accueil app.get('/', (req, res) => { res.sendFile(path.join(__dirname, 'public', 'index.html')); }); // Démarrer le serveur app.listen(port, '0.0.0.0', () => { console.log(`Serveur démarré sur http://0.0.0.0:${port}`); });