189 lines
6.8 KiB
PHP
Executable File
189 lines
6.8 KiB
PHP
Executable File
|
|
<?php
|
|
/**
|
|
* AUTO-SCHEDULER API
|
|
* Timezone-based automatic campaign scheduling
|
|
*/
|
|
header('Content-Type: application/json');
|
|
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123", [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
|
|
|
|
$action = $_GET['action'] ?? $_POST['action'] ?? '';
|
|
|
|
class AutoScheduler {
|
|
private $pdo;
|
|
|
|
public function __construct($pdo) {
|
|
$this->pdo = $pdo;
|
|
}
|
|
|
|
// Get optimal send time for country
|
|
public function getOptimalTime($countryCode) {
|
|
$profile = $this->pdo->query("SELECT * FROM admin.country_profiles WHERE country_code = '$countryCode'")->fetch(PDO::FETCH_ASSOC);
|
|
if (!$profile) return null;
|
|
|
|
$tz = new DateTimeZone($profile['timezone']);
|
|
$now = new DateTime('now', $tz);
|
|
$currentHour = (int)$now->format('H');
|
|
|
|
$bestHours = explode(',', trim($profile['best_send_hours'], '{}'));
|
|
$nextOptimal = null;
|
|
|
|
foreach ($bestHours as $hour) {
|
|
if ((int)$hour > $currentHour) {
|
|
$nextOptimal = (int)$hour;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If no optimal time today, use first tomorrow
|
|
if (!$nextOptimal && !empty($bestHours)) {
|
|
$nextOptimal = (int)$bestHours[0];
|
|
$now->modify('+1 day');
|
|
}
|
|
|
|
if ($nextOptimal) {
|
|
$now->setTime($nextOptimal, 0);
|
|
}
|
|
|
|
return [
|
|
'country' => $profile['country_name'],
|
|
'timezone' => $profile['timezone'],
|
|
'current_local_time' => (new DateTime('now', $tz))->format('H:i'),
|
|
'next_optimal_time' => $now->format('Y-m-d H:i'),
|
|
'best_hours' => $bestHours,
|
|
'best_isps' => explode(',', trim($profile['best_isps'] ?? '', '{}')),
|
|
'avg_open_rate' => $profile['avg_open_rate']
|
|
];
|
|
}
|
|
|
|
// Get all countries ready to send now
|
|
public function getReadyToSend() {
|
|
$countries = $this->pdo->query("SELECT * FROM admin.country_profiles")->fetchAll(PDO::FETCH_ASSOC);
|
|
$ready = [];
|
|
|
|
foreach ($countries as $c) {
|
|
try {
|
|
$tz = new DateTimeZone($c['timezone']);
|
|
$now = new DateTime('now', $tz);
|
|
$currentHour = (int)$now->format('H');
|
|
|
|
$bestHours = explode(',', trim($c['best_send_hours'], '{}'));
|
|
if (in_array($currentHour, array_map('intval', $bestHours))) {
|
|
$ready[] = [
|
|
'country_code' => $c['country_code'],
|
|
'country_name' => $c['country_name'],
|
|
'local_time' => $now->format('H:i'),
|
|
'status' => 'OPTIMAL',
|
|
'best_isps' => $c['best_isps'],
|
|
'avg_open_rate' => $c['avg_open_rate']
|
|
];
|
|
}
|
|
} catch (Exception $e) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return $ready;
|
|
}
|
|
|
|
// Schedule campaign based on targeting rules
|
|
public function scheduleByRule($ruleId) {
|
|
$rule = $this->pdo->query("SELECT * FROM admin.targeting_rules WHERE id = $ruleId")->fetch(PDO::FETCH_ASSOC);
|
|
if (!$rule) return ['error' => 'Rule not found'];
|
|
|
|
$countries = explode(',', trim($rule['country_codes'], '{}'));
|
|
$schedule = [];
|
|
|
|
foreach ($countries as $code) {
|
|
$code = trim($code, '"');
|
|
$optimal = $this->getOptimalTime($code);
|
|
if ($optimal) {
|
|
$schedule[] = [
|
|
'country' => $code,
|
|
'send_at' => $optimal['next_optimal_time'],
|
|
'local_time' => $optimal['current_local_time']
|
|
];
|
|
}
|
|
}
|
|
|
|
return [
|
|
'rule' => $rule['name'],
|
|
'schedule' => $schedule,
|
|
'max_volume' => $rule['max_daily_volume']
|
|
];
|
|
}
|
|
|
|
// Get global overview
|
|
public function getGlobalOverview() {
|
|
$countries = $this->pdo->query("SELECT * FROM admin.country_profiles ORDER BY avg_open_rate DESC")->fetchAll(PDO::FETCH_ASSOC);
|
|
$overview = [];
|
|
|
|
foreach ($countries as $c) {
|
|
try {
|
|
$tz = new DateTimeZone($c['timezone']);
|
|
$now = new DateTime('now', $tz);
|
|
$currentHour = (int)$now->format('H');
|
|
|
|
$bestHours = explode(',', trim($c['best_send_hours'], '{}'));
|
|
$isOptimal = in_array($currentHour, array_map('intval', $bestHours));
|
|
$isSleeping = $currentHour < 7 || $currentHour > 21;
|
|
|
|
$status = 'waiting';
|
|
if ($isOptimal) $status = 'optimal';
|
|
if ($isSleeping) $status = 'sleeping';
|
|
|
|
$overview[] = [
|
|
'country_code' => $c['country_code'],
|
|
'country_name' => $c['country_name'],
|
|
'local_time' => $now->format('H:i'),
|
|
'status' => $status,
|
|
'avg_open_rate' => $c['avg_open_rate'],
|
|
'gdpr' => $c['gdpr_compliant']
|
|
];
|
|
} catch (Exception $e) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
return $overview;
|
|
}
|
|
}
|
|
|
|
$scheduler = new AutoScheduler($pdo);
|
|
|
|
switch ($action) {
|
|
case 'optimal':
|
|
$country = $_GET['country'] ?? 'DE';
|
|
echo json_encode($scheduler->getOptimalTime($country));
|
|
break;
|
|
case 'ready':
|
|
echo json_encode(['ready_countries' => $scheduler->getReadyToSend()]);
|
|
break;
|
|
case 'schedule':
|
|
$ruleId = $_GET['rule_id'] ?? 1;
|
|
echo json_encode($scheduler->scheduleByRule($ruleId));
|
|
break;
|
|
case 'overview':
|
|
echo json_encode(['countries' => $scheduler->getGlobalOverview()]);
|
|
break;
|
|
case 'rules':
|
|
$rules = $pdo->query("SELECT * FROM admin.targeting_rules WHERE is_active = true")->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['rules' => $rules]);
|
|
break;
|
|
case 'countries':
|
|
$countries = $pdo->query("SELECT * FROM admin.country_profiles ORDER BY avg_open_rate DESC")->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['countries' => $countries]);
|
|
break;
|
|
case 'stats':
|
|
$stats = $pdo->query("SELECT * FROM admin.country_daily_stats WHERE date >= CURRENT_DATE - 7 ORDER BY date DESC, opens DESC")->fetchAll(PDO::FETCH_ASSOC);
|
|
echo json_encode(['stats' => $stats]);
|
|
break;
|
|
default:
|
|
echo json_encode([
|
|
'name' => 'Auto-Scheduler API',
|
|
'actions' => ['optimal', 'ready', 'schedule', 'overview', 'rules', 'countries', 'stats'],
|
|
'description' => 'Timezone-based automatic campaign scheduling'
|
|
]);
|
|
}
|
|
|