Files
wevads-platform/scripts/api_send-workflow-api.php
2026-02-26 04:53:11 +01:00

435 lines
18 KiB
PHP
Executable File

<?php
/**
* SEND WORKFLOW API
* Suppression, Warmup, Seeds, Winning, Inbox Monitoring
*/
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
$db = new PDO("pgsql:host=127.0.0.1;dbname=adx_system", "admin", "admin123");
$dbClients = new PDO("pgsql:host=127.0.0.1;dbname=adx_clients", "admin", "admin123");
$action = $_POST['action'] ?? $_GET['action'] ?? '';
$response = ['success' => false, 'error' => 'Unknown action'];
switch ($action) {
// ==================== SUPPRESSION (Blacklist) ====================
case 'run_suppression':
$config_id = intval($_POST['config_id']);
// Get config
$config = $db->query("SELECT * FROM admin.send_configs WHERE id = $config_id")->fetch(PDO::FETCH_ASSOC);
$schema = $config['list_schema'];
$table = $config['list_table'];
// Count blacklisted emails in the list
$countBefore = $dbClients->query("SELECT COUNT(*) FROM \"$schema\".\"$table\"")->fetchColumn();
// Get blacklist emails for this ISP
$blacklistEmails = $db->query("SELECT email FROM admin.blacklists WHERE isp = '{$config['isp']}' OR isp IS NULL")->fetchAll(PDO::FETCH_COLUMN);
if (count($blacklistEmails) > 0) {
// Create temp table with blacklist
$dbClients->exec("CREATE TEMP TABLE temp_blacklist (email VARCHAR(255))");
$stmt = $dbClients->prepare("INSERT INTO temp_blacklist VALUES (?)");
foreach ($blacklistEmails as $email) {
$stmt->execute([$email]);
}
// Delete from list
$deleted = $dbClients->exec("DELETE FROM \"$schema\".\"$table\" WHERE email IN (SELECT email FROM temp_blacklist)");
$dbClients->exec("DROP TABLE temp_blacklist");
} else {
$deleted = 0;
}
$countAfter = $dbClients->query("SELECT COUNT(*) FROM \"$schema\".\"$table\"")->fetchColumn();
// Update config
$db->prepare("UPDATE admin.send_configs SET suppression_done = TRUE, suppression_count = ?, total_recipients = ? WHERE id = ?")
->execute([$deleted, $countAfter, $config_id]);
$response = [
'success' => true,
'before' => $countBefore,
'after' => $countAfter,
'suppressed' => $deleted,
'blacklist_size' => count($blacklistEmails)
];
break;
case 'add_to_blacklist':
$emails = $_POST['emails'] ?? ''; // comma separated or array
$source = $_POST['source'] ?? 'manual';
$isp = $_POST['isp'] ?? null;
if (is_string($emails)) {
$emails = array_map('trim', explode(',', $emails));
}
$added = 0;
$stmt = $db->prepare("INSERT INTO admin.blacklists (email, source, isp) VALUES (?, ?, ?) ON CONFLICT (email) DO NOTHING");
foreach ($emails as $email) {
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
$stmt->execute([$email, $source, $isp]);
$added++;
}
}
$response = ['success' => true, 'added' => $added];
break;
case 'get_blacklist_stats':
$stats = $db->query("SELECT
COUNT(*) as total,
COUNT(CASE WHEN source = 'bounce' THEN 1 END) as bounces,
COUNT(CASE WHEN source = 'complaint' THEN 1 END) as complaints,
COUNT(CASE WHEN source = 'unsubscribe' THEN 1 END) as unsubscribes,
COUNT(CASE WHEN source = 'manual' THEN 1 END) as manual
FROM admin.blacklists")->fetch(PDO::FETCH_ASSOC);
$response = ['success' => true, 'stats' => $stats];
break;
// ==================== WARMUP ====================
case 'get_warmup_status':
$type = $_GET['type'] ?? 'all'; // ip, domain, account, all
$sql = "SELECT * FROM admin.warmup_status";
if ($type !== 'all') {
$sql .= " WHERE type = '$type'";
}
$sql .= " ORDER BY warmup_day DESC, inbox_rate DESC";
$warmups = $db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
$response = ['success' => true, 'warmups' => $warmups];
break;
case 'update_warmup':
$id = intval($_POST['id']);
$volume_sent = intval($_POST['volume_sent'] ?? 0);
$inbox_rate = floatval($_POST['inbox_rate'] ?? 0);
$spam_rate = floatval($_POST['spam_rate'] ?? 0);
// Update stats
$db->prepare("UPDATE admin.warmup_status SET
current_volume = current_volume + ?,
inbox_rate = ?,
spam_rate = ?,
last_send = NOW(),
reputation_score = GREATEST(0, reputation_score - CASE WHEN ? > 20 THEN 10 WHEN ? > 10 THEN 5 ELSE 0 END)
WHERE id = ?")
->execute([$volume_sent, $inbox_rate, $spam_rate, $spam_rate, $spam_rate, $id]);
// Check if burned (spam > 30%)
if ($spam_rate > 30) {
$db->prepare("UPDATE admin.warmup_status SET status = 'burned' WHERE id = ?")->execute([$id]);
}
// Progress warmup day
$warmup = $db->query("SELECT * FROM admin.warmup_status WHERE id = $id")->fetch(PDO::FETCH_ASSOC);
if ($warmup['current_volume'] >= $warmup['daily_limit']) {
$newDay = $warmup['warmup_day'] + 1;
$newLimit = min($warmup['max_volume'], $warmup['daily_limit'] * 1.5); // +50% par jour
$db->prepare("UPDATE admin.warmup_status SET warmup_day = ?, daily_limit = ?, current_volume = 0 WHERE id = ?")
->execute([$newDay, $newLimit, $id]);
// Check if ready
if ($newLimit >= $warmup['max_volume'] && $inbox_rate > 80) {
$db->prepare("UPDATE admin.warmup_status SET status = 'ready' WHERE id = ?")->execute([$id]);
}
}
$response = ['success' => true];
break;
case 'add_warmup':
$type = $_POST['type']; // ip, domain, account
$identifier = $_POST['identifier'];
$server_id = intval($_POST['server_id'] ?? 0);
$max_volume = intval($_POST['max_volume'] ?? 50000);
$db->prepare("INSERT INTO admin.warmup_status (type, identifier, server_id, max_volume, daily_limit)
VALUES (?, ?, ?, ?, 100) ON CONFLICT (type, identifier) DO NOTHING")
->execute([$type, $identifier, $server_id ?: null, $max_volume]);
$response = ['success' => true];
break;
// ==================== SEED TESTING ====================
case 'get_seeds':
$isp = $_GET['isp'] ?? '';
$sql = "SELECT * FROM admin.seed_accounts WHERE status = 'active'";
if ($isp) $sql .= " AND isp = '$isp'";
$seeds = $db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
$response = ['success' => true, 'seeds' => $seeds];
break;
case 'check_seeds':
$config_id = intval($_POST['config_id']);
$drop_number = intval($_POST['drop_number'] ?? 1);
// Get seeds for the ISP
$config = $db->query("SELECT * FROM admin.send_configs WHERE id = $config_id")->fetch(PDO::FETCH_ASSOC);
$seeds = $db->query("SELECT * FROM admin.seed_accounts WHERE status = 'active' AND isp = '{$config['isp']}'")->fetchAll(PDO::FETCH_ASSOC);
$results = [];
$inboxCount = 0;
$spamCount = 0;
foreach ($seeds as $seed) {
// Connect to IMAP and check
$folder = checkSeedInbox($seed);
if ($folder == 'inbox') $inboxCount++;
elseif ($folder == 'spam') $spamCount++;
$results[] = ['seed_id' => $seed['id'], 'email' => $seed['email'], 'folder' => $folder];
// Log result
$db->prepare("INSERT INTO admin.seed_results (send_config_id, drop_number, seed_id, folder) VALUES (?, ?, ?, ?)")
->execute([$config_id, $drop_number, $seed['id'], $folder]);
}
$total = count($seeds);
$inboxRate = $total > 0 ? ($inboxCount / $total) * 100 : 0;
// Log monitoring
$db->prepare("INSERT INTO admin.inbox_monitoring (send_config_id, drop_number, total_inbox, total_spam, inbox_rate) VALUES (?, ?, ?, ?, ?)")
->execute([$config_id, $drop_number, $inboxCount, $spamCount, $inboxRate]);
// Check if should auto-stop
$autoStopped = false;
if ($config['auto_stop_on_spam'] && $inboxRate < $config['inbox_threshold']) {
$db->prepare("UPDATE admin.send_configs SET status = 'paused' WHERE id = ?")->execute([$config_id]);
$db->prepare("INSERT INTO admin.send_alerts (send_config_id, alert_type, message, severity) VALUES (?, 'inbox_drop', ?, 'critical')")
->execute([$config_id, "Inbox rate dropped to {$inboxRate}% - Auto-stopped"]);
$autoStopped = true;
}
$response = [
'success' => true,
'results' => $results,
'inbox_count' => $inboxCount,
'spam_count' => $spamCount,
'inbox_rate' => round($inboxRate, 2),
'auto_stopped' => $autoStopped
];
break;
case 'add_seed':
$email = $_POST['email'];
$password = $_POST['password'];
$isp = $_POST['isp'];
// Detect IMAP settings
$imapSettings = [
'gmail' => ['imap.gmail.com', 993],
'hotmail' => ['outlook.office365.com', 993],
'yahoo' => ['imap.mail.yahoo.com', 993],
'gmx' => ['imap.gmx.com', 993],
];
$settings = $imapSettings[$isp] ?? ['imap.' . $isp . '.com', 993];
$db->prepare("INSERT INTO admin.seed_accounts (email, password, isp, imap_host, imap_port) VALUES (?, ?, ?, ?, ?) ON CONFLICT (email) DO NOTHING")
->execute([$email, $password, $isp, $settings[0], $settings[1]]);
$response = ['success' => true];
break;
// ==================== WINNING CONFIGS ====================
case 'extract_winning':
$send_config_id = intval($_POST['send_config_id']);
// Get config with best performance
$config = $db->query("SELECT c.*,
(SELECT AVG(inbox_rate) FROM admin.inbox_monitoring WHERE send_config_id = c.id) as avg_inbox
FROM admin.send_configs c WHERE c.id = $send_config_id")->fetch(PDO::FETCH_ASSOC);
if ($config['avg_inbox'] >= 70) {
$db->prepare("INSERT INTO admin.winning_configs
(name, isp, country, inbox_rate, source_send_id)
VALUES (?, ?, ?, ?, ?)")
->execute([
"Winner_{$config['isp']}_{$config['country']}_" . date('Ymd'),
$config['isp'],
$config['country'],
$config['avg_inbox'],
$send_config_id
]);
$response = ['success' => true, 'inbox_rate' => $config['avg_inbox']];
} else {
$response = ['success' => false, 'error' => 'Inbox rate too low: ' . $config['avg_inbox']];
}
break;
case 'get_winning_configs':
$isp = $_GET['isp'] ?? '';
$sql = "SELECT * FROM admin.winning_configs WHERE status = 'active'";
if ($isp) $sql .= " AND isp = '$isp'";
$sql .= " ORDER BY inbox_rate DESC";
$configs = $db->query($sql)->fetchAll(PDO::FETCH_ASSOC);
$response = ['success' => true, 'configs' => $configs];
break;
case 'apply_winning_config':
$config_id = intval($_POST['config_id']);
$winning_id = intval($_POST['winning_id']);
$db->prepare("UPDATE admin.send_configs SET winning_config_id = ? WHERE id = ?")->execute([$winning_id, $config_id]);
$db->prepare("UPDATE admin.winning_configs SET usage_count = usage_count + 1 WHERE id = ?")->execute([$winning_id]);
$response = ['success' => true];
break;
// ==================== INBOX MONITORING (Real-time) ====================
case 'monitor_inbox_realtime':
$config_id = intval($_POST['config_id']);
$drop_number = intval($_POST['drop_number'] ?? 1);
// Get current inbox stats
$stats = $db->query("SELECT * FROM admin.inbox_monitoring
WHERE send_config_id = $config_id AND drop_number = $drop_number
ORDER BY check_time DESC LIMIT 1")->fetch(PDO::FETCH_ASSOC);
// Get config threshold
$config = $db->query("SELECT * FROM admin.send_configs WHERE id = $config_id")->fetch(PDO::FETCH_ASSOC);
$shouldStop = false;
$alert = null;
if ($stats && $stats['inbox_rate'] < $config['inbox_threshold']) {
$shouldStop = true;
$alert = "Inbox rate dropped from previous to {$stats['inbox_rate']}%";
// Auto-stop if enabled
if ($config['auto_stop_on_spam'] && !$stats['auto_stopped']) {
$db->prepare("UPDATE admin.send_configs SET status = 'paused' WHERE id = ?")->execute([$config_id]);
$db->prepare("UPDATE admin.inbox_monitoring SET auto_stopped = TRUE WHERE id = ?")->execute([$stats['id']]);
// Stop servers
$serverIds = trim($config['server_ids'], '{}');
if ($serverIds) {
$db->exec("UPDATE mta.servers SET provider_status = 'stopped' WHERE id IN ($serverIds)");
}
// Create alert
$db->prepare("INSERT INTO admin.send_alerts (send_config_id, alert_type, message, severity) VALUES (?, 'spam_detected', ?, 'critical')")
->execute([$config_id, $alert]);
}
}
$response = [
'success' => true,
'stats' => $stats,
'threshold' => $config['inbox_threshold'],
'should_stop' => $shouldStop,
'alert' => $alert,
'auto_stopped' => $stats['auto_stopped'] ?? false
];
break;
// ==================== S3 INTEGRATION ====================
case 'upload_to_s3':
$sponsor_id = intval($_POST['sponsor_id']);
$file = $_FILES['file'] ?? null;
if (!$file) {
$response = ['success' => false, 'error' => 'No file'];
break;
}
// Get sponsor S3 config
$sponsor = $db->query("SELECT * FROM admin.sponsors WHERE id = $sponsor_id")->fetch(PDO::FETCH_ASSOC);
if (!$sponsor['s3_bucket']) {
$response = ['success' => false, 'error' => 'No S3 configured for sponsor'];
break;
}
// Upload using AWS SDK (simplified)
$s3Key = "images/" . date('Y/m/') . uniqid() . "_" . $file['name'];
$s3Url = "https://{$sponsor['s3_bucket']}.s3.{$sponsor['s3_region']}.amazonaws.com/$s3Key";
// In production, use AWS SDK:
// $s3Client->putObject(['Bucket' => $sponsor['s3_bucket'], 'Key' => $s3Key, 'Body' => file_get_contents($file['tmp_name'])]);
// Log asset
$db->prepare("INSERT INTO admin.s3_assets (sponsor_id, asset_type, filename, s3_key, s3_url) VALUES (?, ?, ?, ?, ?)")
->execute([$sponsor_id, 'image', $file['name'], $s3Key, $s3Url]);
$response = ['success' => true, 's3_url' => $s3Url, 's3_key' => $s3Key];
break;
case 'get_s3_assets':
$sponsor_id = intval($_GET['sponsor_id']);
$assets = $db->query("SELECT * FROM admin.s3_assets WHERE sponsor_id = $sponsor_id ORDER BY uploaded_at DESC")->fetchAll(PDO::FETCH_ASSOC);
$response = ['success' => true, 'assets' => $assets];
break;
// ==================== COMPLETE WORKFLOW ====================
case 'pre_send_checklist':
$config_id = intval($_GET['config_id']);
$config = $db->query("SELECT * FROM admin.send_configs WHERE id = $config_id")->fetch(PDO::FETCH_ASSOC);
$checklist = [
'suppression_done' => $config['suppression_done'],
'servers_assigned' => !empty($config['server_ids']),
'seeds_available' => $db->query("SELECT COUNT(*) FROM admin.seed_accounts WHERE status = 'active' AND isp = '{$config['isp']}'")->fetchColumn() > 0,
'warmup_ready' => true, // Check warmup status
'winning_config' => !empty($config['winning_config_id']),
'tracking_configured' => !empty($config['tracking_domain']),
'images_uploaded' => !empty($config['image_url']),
];
$allReady = !in_array(false, $checklist);
$response = ['success' => true, 'checklist' => $checklist, 'all_ready' => $allReady];
break;
}
// Helper function to check seed inbox
function checkSeedInbox($seed) {
// Simplified - in production use IMAP
try {
$inbox = @imap_open(
"{{$seed['imap_host']}:{$seed['imap_port']}/imap/ssl}INBOX",
$seed['email'],
$seed['password']
);
if ($inbox) {
// Search for recent emails
$emails = imap_search($inbox, 'SINCE "' . date('d-M-Y', strtotime('-1 hour')) . '"');
imap_close($inbox);
return $emails ? 'inbox' : 'not_found';
}
// Check spam folder
$spam = @imap_open(
"{{$seed['imap_host']}:{$seed['imap_port']}/imap/ssl}[Gmail]/Spam",
$seed['email'],
$seed['password']
);
if ($spam) {
$emails = imap_search($spam, 'SINCE "' . date('d-M-Y', strtotime('-1 hour')) . '"');
imap_close($spam);
return $emails ? 'spam' : 'not_found';
}
} catch (Exception $e) {
return 'error';
}
return 'not_found';
}
echo json_encode($response);