($httpCode >= 200 && $httpCode < 400) ? 'ok' : 'error',
'latency' => round($latency, 2),
'http_code' => $httpCode,
'error' => $error ?: ($httpCode ? "HTTP $httpCode" : "Connection failed")
];
}
function notifyStatusChange($url, $oldStatus, $newStatus, $error = null) {
$recipient = 'yumeecute@aol.com';
$time = date('Y-m-d H:i:s');
if ($oldStatus === 'ok' && $newStatus === 'error') {
$subject = "🔴 ALERT: Website Down - $url";
$html = "
Website Down Alert
The following website is currently unresponsive:
URL: $url
Error: $error
Time: $time
This is an automated notification from your Uptime Monitor.
";
} elseif ($oldStatus === 'error' && $newStatus === 'ok') {
$subject = "🟢 RESOLVED: Website Up - $url";
$html = "
Website Back Online
The following website is responding normally again:
URL: $url
Time: $time
This is an automated notification from your Uptime Monitor.
";
} else {
return; // No notification for other transitions
}
MailService::sendMail($recipient, $subject, $html);
}
function isMonitoringEnabled() {
try {
$stmt = db()->prepare("SELECT value FROM settings WHERE `key` = 'monitoring_enabled'");
$stmt->execute();
$val = $stmt->fetchColumn();
return $val === '1';
} catch (Exception $e) {
return false;
}
}
function generateApiKey() {
return bin2hex(random_bytes(32));
}
switch ($action) {
case 'settings':
echo json_encode(['monitoring_enabled' => isMonitoringEnabled()]);
break;
case 'toggle':
$data = json_decode(file_get_contents('php://input'), true);
$enabled = ($data['enabled'] ?? false) ? '1' : '0';
$stmt = db()->prepare("UPDATE settings SET value = ? WHERE `key` = 'monitoring_enabled'");
$stmt->execute([$enabled]);
echo json_encode(['success' => true, 'monitoring_enabled' => $enabled === '1']);
break;
case 'list':
$stmt = db()->query("SELECT * FROM urls ORDER BY id DESC");
echo json_encode($stmt->fetchAll());
break;
case 'add':
$data = json_decode(file_get_contents('php://input'), true);
$url = $data['url'] ?? '';
if (filter_var($url, FILTER_VALIDATE_URL)) {
// Get default team_id or first available
$team_id = db()->query("SELECT id FROM teams LIMIT 1")->fetchColumn();
if (!$team_id) {
// Should not happen with migrations, but safety first
db()->query("INSERT INTO teams (name, owner_email) VALUES ('Default Team', 'admin@example.com')");
$team_id = db()->lastInsertId();
}
$stmt = db()->prepare("INSERT INTO urls (url, team_id) VALUES (?, ?)");
$stmt->execute([$url, $team_id]);
echo json_encode(['success' => true, 'id' => db()->lastInsertId()]);
} else {
echo json_encode(['success' => false, 'error' => 'Invalid URL. Use http:// or https://']);
}
break;
case 'delete':
$data = json_decode(file_get_contents('php://input'), true);
$id = $data['id'] ?? 0;
$stmt = db()->prepare("DELETE FROM urls WHERE id = ?");
$stmt->execute([$id]);
echo json_encode(['success' => true]);
break;
case 'check':
if (!isMonitoringEnabled()) {
echo json_encode(['info' => 'Monitoring is disabled globally']);
exit;
}
$stmt = db()->query("SELECT * FROM urls WHERE is_active = 1");
$urls = $stmt->fetchAll();
$results = [];
foreach ($urls as $row) {
$res = ping($row['url']);
// Notify on change
notifyStatusChange($row['url'], $row['last_status'], $res['status'], $res['error']);
// Update URL status
$upd = db()->prepare("UPDATE urls SET last_status = ?, last_latency = ?, last_checked_at = NOW() WHERE id = ?");
$upd->execute([$res['status'], $res['latency'], $row['id']]);
// Insert log
$log = db()->prepare("INSERT INTO logs (url_id, status, latency, error_message) VALUES (?, ?, ?, ?)");
$log->execute([$row['id'], $res['status'], $res['latency'], $res['status'] === 'error' ? $res['error'] : null]);
$results[] = [
'id' => $row['id'],
'url' => $row['url'],
'status' => $res['status'],
'latency' => $res['latency'],
'error' => $res['error']
];
}
echo json_encode($results);
break;
case 'logs':
$url_id = $_GET['url_id'] ?? null;
if ($url_id) {
$stmt = db()->prepare("SELECT * FROM logs WHERE url_id = ? ORDER BY id DESC LIMIT 24");
$stmt->execute([$url_id]);
} else {
$stmt = db()->query("SELECT l.*, u.url FROM logs l JOIN urls u ON l.url_id = u.id ORDER BY l.id DESC LIMIT 50");
}
echo json_encode($stmt->fetchAll());
break;
case 'stats':
$res = [
'total' => db()->query("SELECT COUNT(*) FROM urls")->fetchColumn(),
'up' => db()->query("SELECT COUNT(*) FROM urls WHERE last_status = 'ok'")->fetchColumn(),
'down' => db()->query("SELECT COUNT(*) FROM urls WHERE last_status = 'error'")->fetchColumn(),
'avg_latency' => db()->query("SELECT AVG(last_latency) FROM urls")->fetchColumn() ?: 0,
'recent_errors' => db()->query("SELECT l.*, u.url FROM logs l JOIN urls u ON l.url_id = u.id WHERE l.status = 'error' ORDER BY l.id DESC LIMIT 10")->fetchAll()
];
echo json_encode($res);
break;
case 'teams':
$stmt = db()->query("SELECT * FROM teams ORDER BY id DESC");
echo json_encode($stmt->fetchAll());
break;
case 'create_team':
$data = json_decode(file_get_contents('php://input'), true);
$name = $data['name'] ?? '';
$email = $data['email'] ?? 'yumeecute@aol.com';
if ($name) {
$stmt = db()->prepare("INSERT INTO teams (name, owner_email) VALUES (?, ?)");
$stmt->execute([$name, $email]);
echo json_encode(['success' => true, 'id' => db()->lastInsertId()]);
} else {
echo json_encode(['success' => false, 'error' => 'Team name required']);
}
break;
case 'members':
$team_id = $_GET['team_id'] ?? null;
if (!$team_id) {
$team_id = db()->query("SELECT id FROM teams LIMIT 1")->fetchColumn();
}
if ($team_id) {
$stmt = db()->prepare("SELECT * FROM team_members WHERE team_id = ?");
$stmt->execute([$team_id]);
echo json_encode($stmt->fetchAll());
} else {
echo json_encode([]);
}
break;
case 'invite':
$data = json_decode(file_get_contents('php://input'), true);
$email = $data['email'] ?? '';
$team_id = $data['team_id'] ?? db()->query("SELECT id FROM teams LIMIT 1")->fetchColumn();
if (filter_var($email, FILTER_VALIDATE_EMAIL) && $team_id) {
$stmt = db()->prepare("INSERT INTO team_members (team_id, email, status) VALUES (?, ?, 'invited')");
$stmt->execute([$team_id, $email]);
// Send invite email
$subject = "Invitation to join Team on 𝐌𝐨𝐧𝐢𝐭𝐨𝐫 𝐔𝐩𝐭𝐢𝐦𝐞 𝐛𝐲 𝐘𝐮𝐦𝐞𝐞";
$html = "You have been invited to join a team.
Accept Invitation
";
MailService::sendMail($email, $subject, $html);
echo json_encode(['success' => true]);
} else {
echo json_encode(['success' => false, 'error' => 'Invalid email or team ID']);
}
break;
case 'keys':
$team_id = $_GET['team_id'] ?? db()->query("SELECT id FROM teams LIMIT 1")->fetchColumn();
if ($team_id) {
$stmt = db()->prepare("SELECT * FROM api_keys WHERE team_id = ?");
$stmt->execute([$team_id]);
echo json_encode($stmt->fetchAll());
} else {
echo json_encode([]);
}
break;
case 'generate_key':
$data = json_decode(file_get_contents('php://input'), true);
$label = $data['label'] ?? 'New Key';
$team_id = $data['team_id'] ?? db()->query("SELECT id FROM teams LIMIT 1")->fetchColumn();
if ($team_id) {
$key = generateApiKey();
$stmt = db()->prepare("INSERT INTO api_keys (team_id, api_key, label) VALUES (?, ?, ?)");
$stmt->execute([$team_id, $key, $label]);
echo json_encode(['success' => true, 'key' => $key]);
} else {
echo json_encode(['success' => false, 'error' => 'No team available']);
}
break;
default:
echo json_encode(['error' => 'Unknown action']);
break;
}