Files
wevads-platform/public/data-pipeline.php
2026-04-07 03:04:16 +02:00

335 lines
15 KiB
PHP

<?php
require_once('/opt/wevads/config/credentials.php');
/**
* DATA PIPELINE - Flux complet de collecte vers envoi
*/
$pdo = get_pdo('adx_system');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Actions API
if (isset($_GET['action'])) {
header('Content-Type: application/json');
switch($_GET['action']) {
case 'transfer_harvested_to_senddata':
// Transférer harvested_leads → send_data
try {
$count = $pdo->query("SELECT COUNT(*) FROM admin.harvested_leads WHERE email NOT IN (SELECT email FROM admin.send_data)")->fetchColumn();
if ($count > 0) {
$pdo->exec("INSERT INTO admin.send_data (email, first_name, last_name, isp, country, engagement_score, source, status)
SELECT email, first_name, last_name, isp, country, engagement_score, source_type, 'active'
FROM admin.harvested_leads
WHERE email NOT IN (SELECT email FROM admin.send_data)");
}
echo json_encode(['success' => true, 'transferred' => $count]);
} catch(Exception $e) {
echo json_encode(['error' => $e->getMessage()]);
}
break;
case 'create_list_from_senddata':
// Créer une send_list à partir de send_data
try {
$name = $_GET['name'] ?? 'Liste ' . date('Y-m-d H:i');
$stmt = $pdo->prepare("INSERT INTO admin.send_lists (name, description, contact_count, status) VALUES (?, 'Auto-generated', 0, 'active') RETURNING id");
$stmt->execute([$name]);
$listId = $stmt->fetchColumn();
// Ajouter les contacts
$pdo->exec("INSERT INTO admin.send_list_contacts (list_id, contact_id)
SELECT $listId, id FROM admin.send_data WHERE status = 'active'
ON CONFLICT DO NOTHING");
$count = $pdo->query("SELECT COUNT(*) FROM admin.send_list_contacts WHERE list_id = $listId")->fetchColumn();
$pdo->exec("UPDATE admin.send_lists SET contact_count = $count WHERE id = $listId");
echo json_encode(['success' => true, 'list_id' => $listId, 'contacts' => $count]);
} catch(Exception $e) {
echo json_encode(['error' => $e->getMessage()]);
}
break;
case 'run_extraction':
// Simuler une extraction (à connecter au vrai extracteur)
echo json_encode(['success' => true, 'message' => 'Extraction lancée - Ouvre /tools/mailbox-extractor.html']);
break;
case 'stats':
$stats = [];
try { $stats['seeds'] = $pdo->query("SELECT COUNT(*) FROM admin.brain_seeds")->fetchColumn(); } catch(Exception $e) { $stats['seeds'] = 0; }
try { $stats['seeds_active'] = $pdo->query("SELECT COUNT(*) FROM admin.brain_seeds WHERE is_active=true")->fetchColumn(); } catch(Exception $e) { $stats['seeds_active'] = 0; }
try { $stats['harvested'] = $pdo->query("SELECT COUNT(*) FROM admin.harvested_leads")->fetchColumn(); } catch(Exception $e) { $stats['harvested'] = 0; }
try { $stats['send_data'] = $pdo->query("SELECT COUNT(*) FROM admin.send_data")->fetchColumn(); } catch(Exception $e) { $stats['send_data'] = 0; }
try { $stats['send_lists'] = $pdo->query("SELECT COUNT(*) FROM admin.send_lists")->fetchColumn(); } catch(Exception $e) { $stats['send_lists'] = 0; }
try { $stats['campaigns'] = $pdo->query("SELECT COUNT(*) FROM admin.campaigns")->fetchColumn(); } catch(Exception $e) { $stats['campaigns'] = 0; }
try { $stats['sending'] = $pdo->query("SELECT COUNT(*) FROM admin.campaigns WHERE status='sending'")->fetchColumn(); } catch(Exception $e) { $stats['sending'] = 0; }
echo json_encode($stats);
break;
}
exit;
}
// Stats
$s = [];
try { $s['seeds'] = $pdo->query("SELECT COUNT(*) FROM admin.brain_seeds")->fetchColumn(); } catch(Exception $e) { $s['seeds'] = 0; }
try { $s['seeds_active'] = $pdo->query("SELECT COUNT(*) FROM admin.brain_seeds WHERE is_active=true")->fetchColumn(); } catch(Exception $e) { $s['seeds_active'] = 0; }
try { $s['harvested'] = $pdo->query("SELECT COUNT(*) FROM admin.harvested_leads")->fetchColumn(); } catch(Exception $e) { $s['harvested'] = 0; }
try { $s['send_data'] = $pdo->query("SELECT COUNT(*) FROM admin.send_data")->fetchColumn(); } catch(Exception $e) { $s['send_data'] = 0; }
try { $s['send_lists'] = $pdo->query("SELECT COUNT(*) FROM admin.send_lists")->fetchColumn(); } catch(Exception $e) { $s['send_lists'] = 0; }
try { $s['list_contacts'] = $pdo->query("SELECT COUNT(*) FROM admin.send_list_contacts")->fetchColumn(); } catch(Exception $e) { $s['list_contacts'] = 0; }
try { $s['campaigns'] = $pdo->query("SELECT COUNT(*) FROM admin.campaigns")->fetchColumn(); } catch(Exception $e) { $s['campaigns'] = 0; }
try { $s['sending'] = $pdo->query("SELECT COUNT(*) FROM admin.campaigns WHERE status='sending'")->fetchColumn(); } catch(Exception $e) { $s['sending'] = 0; }
// Seeds
$seeds = [];
try { $seeds = $pdo->query("SELECT email,isp,country,is_active FROM admin.brain_seeds ORDER BY id LIMIT 10")->fetchAll(PDO::FETCH_ASSOC); } catch(Exception $e) {}
// Send Lists
$lists = [];
try { $lists = $pdo->query("SELECT id,name,contact_count,status FROM admin.send_lists ORDER BY id DESC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC); } catch(Exception $e) {}
?>
<!DOCTYPE html>
<html><head>
<meta charset="UTF-8"><title>Data Pipeline - WEVAL</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:system-ui;background:#0a0a0f;color:#e2e8f0;min-height:100vh}
.header{background:linear-gradient(135deg,#1e3a5f,#7c3aed);padding:20px 25px;border-bottom:2px solid #a855f7}
.header h1{font-size:1.5rem;color:white;display:flex;align-items:center;gap:10px}
.container{padding:20px;max-width:1400px;margin:0 auto}
/* Pipeline */
.pipeline{display:flex;align-items:stretch;gap:0;margin:30px 0;flex-wrap:wrap}
.stage{flex:1;min-width:180px;background:#12121a;border-radius:16px;padding:20px;text-align:center;position:relative;border:2px solid #333}
.stage.active{border-color:#10b981;box-shadow:0 0 20px rgba(16,185,129,0.3)}
.stage.warning{border-color:#f59e0b}
.stage.error{border-color:#ef4444}
.stage-icon{font-size:2.5rem;margin-bottom:10px}
.stage-title{font-size:1rem;font-weight:bold;color:#5eead4;margin-bottom:5px}
.stage-count{font-size:2rem;font-weight:bold;margin:10px 0}
.stage-count.zero{color:#ef4444}
.stage-count.ok{color:#10b981}
.stage-label{font-size:0.8rem;opacity:0.7}
.stage-btn{margin-top:15px;padding:10px 15px;border:none;border-radius:8px;cursor:pointer;font-size:0.85rem;width:100%}
.stage-btn.primary{background:#3b82f6;color:white}
.stage-btn.success{background:#10b981;color:white}
.stage-btn.warning{background:#f59e0b;color:black}
.stage-btn:hover{opacity:0.8}
.stage-btn:disabled{opacity:0.5;cursor:not-allowed}
.arrow{display:flex;align-items:center;justify-content:center;font-size:2rem;color:#5eead4;padding:0 10px}
.arrow.broken{color:#ef4444}
/* Status */
.status-box{background:#12121a;border-radius:12px;padding:20px;margin-bottom:20px;border:1px solid #333}
.status-title{color:#5eead4;margin-bottom:15px;font-size:1.1rem}
.status-row{display:flex;justify-content:space-between;padding:10px;background:#1a1a2e;border-radius:8px;margin-bottom:8px}
.status-row.error{border-left:4px solid #ef4444}
.status-row.ok{border-left:4px solid #10b981}
/* Seeds list */
.seed-item{display:flex;justify-content:space-between;padding:10px;background:#1a1a2e;border-radius:8px;margin-bottom:8px;font-size:0.85rem}
.seed-email{font-family:monospace}
.seed-badge{padding:3px 10px;border-radius:12px;font-size:0.75rem}
.seed-badge.active{background:rgba(16,185,129,0.2);color:#10b981}
.seed-badge.inactive{background:rgba(239,68,68,0.2);color:#ef4444}
/* Lists */
.list-item{display:flex;justify-content:space-between;padding:12px;background:#1a1a2e;border-radius:8px;margin-bottom:8px}
.list-name{font-weight:bold}
.list-count{color:#5eead4}
.grid{display:grid;gap:20px}
.g2{grid-template-columns:repeat(2,1fr)}
.g3{grid-template-columns:repeat(3,1fr)}
@media(max-width:900px){.g2,.g3{grid-template-columns:1fr}}
.alert{padding:15px;border-radius:10px;margin-bottom:20px}
.alert.error{background:rgba(239,68,68,0.15);border:1px solid #ef4444;color:#fca5a5}
.alert.success{background:rgba(16,185,129,0.15);border:1px solid #10b981;color:#6ee7b7}
.alert.info{background:rgba(59,130,246,0.15);border:1px solid #3b82f6;color:#93c5fd}
.back-link{color:#5eead4;text-decoration:none;margin-bottom:20px;display:inline-block}
.back-link:hover{text-decoration:underline}
#result{margin-top:20px;padding:15px;border-radius:10px;display:none}
</style>
</head><body>
<div class="header">
<h1><i class="fas fa-stream"></i> Data Pipeline - Flux de Données</h1>
</div>
<div class="container">
<a href="/hamid-control-center.php" class="back-link">← Retour au Control Center</a>
<!-- Alerte si pipeline vide -->
<?php if($s['harvested'] == 0 && $s['send_data'] == 0): ?>
<div class="alert error">
<strong>Pipeline vide!</strong> Tu as <?=$s['seeds']?> seeds mais 0 emails collectés. Lance l'extracteur pour commencer.
</div>
<?php endif; ?>
<!-- PIPELINE VISUEL -->
<div class="pipeline">
<!-- Stage 1: Seeds -->
<div class="stage <?=$s['seeds_active']>0?'active':'error'?>">
<div class="stage-icon">🌱</div>
<div class="stage-title">SEEDS</div>
<div class="stage-count <?=$s['seeds']>0?'ok':'zero'?>"><?=$s['seeds']?></div>
<div class="stage-label"><?=$s['seeds_active']?> actifs</div>
<a href="/brain-seeds.html" class="stage-btn primary">Gérer Seeds</a>
</div>
<div class="arrow <?=$s['harvested']==0?'broken':''?>">→</div>
<!-- Stage 2: Extraction -->
<div class="stage <?=$s['harvested']>0?'active':'warning'?>">
<div class="stage-icon">📧</div>
<div class="stage-title">EXTRACTION</div>
<div class="stage-count <?=$s['harvested']>0?'ok':'zero'?>"><?=number_format($s['harvested'])?></div>
<div class="stage-label">emails collectés</div>
<a href="/tools/mailbox-extractor.html" class="stage-btn warning">Lancer Extracteur</a>
</div>
<div class="arrow <?=$s['send_data']==0?'broken':''?>">→</div>
<!-- Stage 3: Send Data -->
<div class="stage <?=$s['send_data']>0?'active':'warning'?>">
<div class="stage-icon">📋</div>
<div class="stage-title">SEND DATA</div>
<div class="stage-count <?=$s['send_data']>0?'ok':'zero'?>"><?=number_format($s['send_data'])?></div>
<div class="stage-label">contacts prêts</div>
<button class="stage-btn success" onclick="transferData()" <?=$s['harvested']==0?'disabled':''?>>
Transférer →
</button>
</div>
<div class="arrow <?=$s['send_lists']==0?'broken':''?>">→</div>
<!-- Stage 4: Lists -->
<div class="stage <?=$s['send_lists']>0?'active':'warning'?>">
<div class="stage-icon">📑</div>
<div class="stage-title">LISTS</div>
<div class="stage-count <?=$s['send_lists']>0?'ok':'zero'?>"><?=$s['send_lists']?></div>
<div class="stage-label"><?=number_format($s['list_contacts'])?> contacts</div>
<button class="stage-btn success" onclick="createList()" <?=$s['send_data']==0?'disabled':''?>>
Créer Liste →
</button>
</div>
<div class="arrow">→</div>
<!-- Stage 5: Campaigns -->
<div class="stage <?=$s['sending']>0?'active':''?>">
<div class="stage-icon">🚀</div>
<div class="stage-title">CAMPAIGNS</div>
<div class="stage-count <?=$s['sending']>0?'ok':'zero'?>"><?=$s['sending']?></div>
<div class="stage-label">en envoi / <?=$s['campaigns']?> total</div>
<a href="/campaigns.html" class="stage-btn primary">Gérer Campaigns</a>
</div>
</div>
<div id="result"></div>
<!-- Détails -->
<div class="grid g2">
<!-- Seeds -->
<div class="status-box">
<div class="status-title">🌱 Seeds Configurés (<?=$s['seeds']?>)</div>
<?php if(empty($seeds)): ?>
<p style="opacity:0.5">Aucun seed configuré</p>
<?php else: foreach($seeds as $seed): ?>
<div class="seed-item">
<span class="seed-email"><?=htmlspecialchars($seed['email'])?></span>
<span><?=htmlspecialchars($seed['isp'] ?? '')?> | <?=htmlspecialchars($seed['country'] ?? '')?></span>
<span class="seed-badge <?=$seed['is_active']?'active':'inactive'?>"><?=$seed['is_active']?'Actif':'Inactif'?></span>
</div>
<?php endforeach; endif; ?>
<a href="/deliverads/import-senddata.php" class="stage-btn primary" style="margin-top:15px">📤 Import Manuel</a>
</div>
<!-- Lists -->
<div class="status-box">
<div class="status-title">📑 Send Lists (<?=$s['send_lists']?>)</div>
<?php if(empty($lists)): ?>
<p style="opacity:0.5">Aucune liste créée</p>
<?php else: foreach($lists as $list): ?>
<div class="list-item">
<span class="list-name"><?=htmlspecialchars($list['name'])?></span>
<span class="list-count"><?=number_format($list['contact_count'])?> contacts</span>
</div>
<?php endforeach; endif; ?>
</div>
</div>
<!-- Actions rapides -->
<div class="status-box">
<div class="status-title">⚡ Actions Rapides</div>
<div style="display:flex;gap:10px;flex-wrap:wrap">
<a href="/tools/mailbox-extractor.html" class="stage-btn warning" style="width:auto">📧 Extracteur</a>
<a href="/deliverads/import-senddata.php" class="stage-btn primary" style="width:auto">📤 Import Data</a>
<a href="/deliverads/crm.php" class="stage-btn primary" style="width:auto">👥 CRM</a>
<a href="/campaigns.html" class="stage-btn success" style="width:auto">🚀 Campaigns</a>
<a href="/hamid-control-center.php" class="stage-btn primary" style="width:auto">🧠 Control Center</a>
</div>
</div>
</div>
<script>
function showResult(msg, type) {
var r = document.getElementById('result');
r.style.display = 'block';
r.className = 'alert ' + type;
r.innerHTML = msg;
}
function transferData() {
showResult('⏳ Transfert en cours...', 'info');
fetch('?action=transfer_harvested_to_senddata')
.then(r => r.json())
.then(data => {
if (data.error) {
showResult('❌ Erreur: ' + data.error, 'error');
} else {
showResult('✅ Transféré: ' + data.transferred + ' contacts', 'success');
setTimeout(() => location.reload(), 2000);
}
});
}
function createList() {
var name = prompt('Nom de la liste:', 'Liste ' + new Date().toISOString().slice(0,10));
if (!name) return;
showResult('⏳ Création en cours...', 'info');
fetch('?action=create_list_from_senddata&name=' + encodeURIComponent(name))
.then(r => r.json())
.then(data => {
if (data.error) {
showResult('❌ Erreur: ' + data.error, 'error');
} else {
showResult('✅ Liste créée: ' + data.contacts + ' contacts', 'success');
setTimeout(() => location.reload(), 2000);
}
});
}
// Auto-refresh stats
setInterval(() => {
fetch('?action=stats').then(r => r.json()).then(data => {
// Update would go here
});
}, 30000);
</script>
</body></html>