PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC] ); $families = $meta->query("SELECT id FROM families")->fetchAll(PDO::FETCH_COLUMN); } catch (Exception $e) { exit("Cannot connect to meta DB: " . $e->getMessage() . "\n"); } foreach ($families as $family_id) { $db_name = 'househub_f' . $family_id; try { $pdo = new PDO( "mysql:host=$DB_HOST;dbname=$db_name;charset=utf8mb4", $DB_USER, $DB_PASS, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC] ); } catch (Exception $e) { continue; } if (!$pdo->query("SHOW TABLES LIKE 'pf_todos'")->fetchColumn()) continue; $ws = $pdo->prepare("SELECT content FROM pf_notes WHERE note_type='todo_settings' AND reference_id='webhook_discord'"); $ws->execute(); $webhook = $ws->fetchColumn(); if (!$webhook) continue; // Daily reminder: fires every day when due_time is reached, resets at midnight $stmt = $pdo->prepare(" SELECT t.id, t.title, t.due_time, l.name AS list_name, l.icon AS list_icon FROM pf_todos t LEFT JOIN pf_todo_lists l ON l.id = t.list_id WHERE t.due_time IS NOT NULL AND t.due_time <= CURTIME() AND t.done = 0 AND (t.notified_date IS NULL OR t.notified_date < CURDATE()) "); $stmt->execute(); foreach ($stmt->fetchAll() as $t) { $time = substr($t['due_time'], 0, 5); $list = $t['list_name'] ? " _({$t['list_icon']} {$t['list_name']})_" : ''; $msg = "⏰ **Rappel** : {$t['title']}{$list} — {$time}"; $ch = curl_init($webhook); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => json_encode(['username' => 'HouseHub Todo', 'content' => $msg]), ]); curl_exec($ch); $ok = curl_getinfo($ch, CURLINFO_HTTP_CODE) < 300; curl_close($ch); if ($ok) { $pdo->prepare("UPDATE pf_todos SET notified_date = CURDATE() WHERE id=?")->execute([$t['id']]); } } }