exec(" CREATE TABLE IF NOT EXISTS user_calendar_integrations ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, provider VARCHAR(50) NOT NULL DEFAULT 'icloud_caldav', username VARCHAR(255) NOT NULL, secret_encrypted TEXT NOT NULL, dav_principal_url VARCHAR(1024) DEFAULT NULL, calendar_url VARCHAR(1024) DEFAULT NULL, status VARCHAR(30) DEFAULT 'connected', last_sync_at DATETIME DEFAULT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uq_user_provider (user_id, provider) )"); // ─── Actions ────────────────────────────────────────────────────────────────── if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!verify_csrf($_POST['csrf_token'] ?? null)) { $error = "Session invalide (CSRF). Rechargez la page."; } else { $action = $_POST['action'] ?? ''; if ($action === 'set_modules' && $family_id) { $all = ['calendar', 'budget', 'holidays', 'gifts', 'garage', 'memo', 'todo', 'calendar_ios']; $enabled = array_values(array_filter($all, fn($m) => isset($_POST['mod_' . $m]))); if (empty($enabled)) { $error = "Vous devez garder au moins un module actif."; } else { $meta_pdo->prepare("UPDATE families SET enabled_modules = ? WHERE id = ?") ->execute([json_encode($enabled), $family_id]); $_SESSION['enabled_modules'] = $enabled; $success = "Modules mis à jour."; } } if ($action === 'set_lang') { $lang = $_POST['lang'] ?? 'fr'; if (in_array($lang, ['fr', 'ca', 'en'])) { $_SESSION['app_lang'] = $lang; $meta_pdo->prepare("UPDATE users SET lang = ? WHERE id = ?") ->execute([$lang, $user_id]); $success = "Language updated."; } } if ($action === 'update_profile') { $display_name = trim($_POST['display_name'] ?? ''); if (!$display_name) { $error = "Le prénom ne peut pas être vide."; } else { $meta_pdo->prepare("UPDATE users SET display_name = ? WHERE id = ?") ->execute([$display_name, $user_id]); $_SESSION['user']['display_name'] = $display_name; $success = "Profil mis à jour."; } } if ($action === 'change_password') { $current = $_POST['current_password'] ?? ''; $new = $_POST['new_password'] ?? ''; $confirm = $_POST['confirm_password'] ?? ''; $row = $meta_pdo->prepare("SELECT password_hash FROM users WHERE id = ?"); $row->execute([$user_id]); $row = $row->fetch(); if (!password_verify($current, $row['password_hash'])) { $error = "Mot de passe actuel incorrect."; } elseif (strlen($new) < 6) { $error = "Le nouveau mot de passe doit faire au moins 6 caractères."; } elseif ($new !== $confirm) { $error = "Les mots de passe ne correspondent pas."; } else { $meta_pdo->prepare("UPDATE users SET password_hash = ? WHERE id = ?") ->execute([password_hash($new, PASSWORD_BCRYPT), $user_id]); $success = "Mot de passe modifié avec succès."; } } if ($action === 'update_family_name' && $family_id) { $name = trim($_POST['family_name'] ?? ''); if ($name) { $meta_pdo->prepare("UPDATE families SET name = ? WHERE id = ?") ->execute([$name, $family_id]); $success = "Nom de l'espace mis à jour."; } } if ($action === 'regen_invite' && $family_id) { $new_code = bin2hex(random_bytes(8)); $meta_pdo->prepare("UPDATE families SET invite_code = ? WHERE id = ?") ->execute([$new_code, $family_id]); $success = "Nouveau code d'invitation généré."; } if ($action === 'upload_home_bg' && $family_id) { $upload_dir = '/uploads/'; if (!is_dir($upload_dir)) @mkdir($upload_dir, 0755, true); $file = $_FILES['home_bg'] ?? null; if ($file && $file['error'] === 0) { $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if (!in_array($ext, ['jpg','jpeg','png','webp'])) { $error = "Format non supporté (jpg, png, webp)."; } else { $dest = $upload_dir . 'home_bg_' . $family_id . '.' . $ext; // Supprimer anciens fichiers de ce family foreach (glob($upload_dir . 'home_bg_' . $family_id . '.*') as $old) @unlink($old); if (move_uploaded_file($file['tmp_name'], $dest)) { $success = "Image d'accueil mise à jour."; } else { $error = "Erreur lors de l'upload."; } } } } if ($action === 'reset_home_bg' && $family_id) { foreach (glob('/uploads/home_bg_' . $family_id . '.*') as $old) @unlink($old); $success = "Image d'accueil réinitialisée."; } if ($action === 'calendar_ios_save') { $username = trim($_POST['icloud_username'] ?? ''); $appPassword = trim($_POST['icloud_app_password'] ?? ''); $calendarUrl = trim($_POST['icloud_calendar_url'] ?? ''); if (!$username || !$appPassword || !$calendarUrl) { $error = "Merci de renseigner identifiant iCloud, mot de passe d'app et URL CalDAV."; } else { try { $encrypted = hh_encrypt_secret($appPassword); $meta_pdo->prepare(" INSERT INTO user_calendar_integrations (user_id, provider, username, secret_encrypted, calendar_url, status, updated_at) VALUES (?, 'icloud_caldav', ?, ?, ?, 'connected', NOW()) ON DUPLICATE KEY UPDATE username=VALUES(username), secret_encrypted=VALUES(secret_encrypted), calendar_url=VALUES(calendar_url), status='connected', updated_at=NOW() ")->execute([$user_id, $username, $encrypted, $calendarUrl]); $success = "Connexion calendrier iOS enregistrée."; } catch (\Throwable $e) { $error = "Impossible d'enregistrer la connexion iOS: " . $e->getMessage(); } } } if ($action === 'calendar_ios_test') { $row = $meta_pdo->prepare("SELECT username, secret_encrypted, calendar_url FROM user_calendar_integrations WHERE user_id = ? AND provider='icloud_caldav'"); $row->execute([$user_id]); $integration = $row->fetch(); if (!$integration) { $error = "Aucune connexion iOS configurée."; } else { try { $pwd = hh_decrypt_secret($integration['secret_encrypted']); $ch = curl_init($integration['calendar_url']); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, CURLOPT_NOBODY => true, CURLOPT_HTTPAUTH => CURLAUTH_BASIC, CURLOPT_USERPWD => $integration['username'] . ':' . $pwd, ]); curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($code >= 200 && $code < 400) { $success = "Connexion iCloud CalDAV valide."; } else { $error = "Test connexion échoué (HTTP $code)."; } } catch (\Throwable $e) { $error = "Test connexion impossible: " . $e->getMessage(); } } } if ($action === 'calendar_ios_disconnect') { $meta_pdo->prepare("DELETE FROM user_calendar_integrations WHERE user_id = ? AND provider='icloud_caldav'")->execute([$user_id]); $success = "Connexion iOS supprimée."; } } } // ─── Chargement données ─────────────────────────────────────────────────────── $user = $meta_pdo->prepare("SELECT * FROM users WHERE id = ?"); $user->execute([$user_id]); $user = $user->fetch(); $family = null; $members = []; if ($family_id) { $fam = $meta_pdo->prepare("SELECT * FROM families WHERE id = ?"); $fam->execute([$family_id]); $family = $fam->fetch(); $mem = $meta_pdo->prepare("SELECT display_name, username, created_at, is_admin FROM users WHERE family_id = ? ORDER BY id"); $mem->execute([$family_id]); $members = $mem->fetchAll(); } $calendarIntegration = $meta_pdo->prepare("SELECT username, calendar_url, status, last_sync_at FROM user_calendar_integrations WHERE user_id = ? AND provider='icloud_caldav'"); $calendarIntegration->execute([$user_id]); $calendarIntegration = $calendarIntegration->fetch(); $pageTitle = "Paramètres — HouseHub"; $activePage = "settings"; require __DIR__ . '/header.php'; ?>

⚙️ Paramètres

🌐 Langue / Language

'; $en_flag = ''; $senyera = ''; $langs = [ 'fr' => ['flag' => $fr_flag, 'label' => 'Français'], 'en' => ['flag' => $en_flag, 'label' => 'English'], 'ca' => ['flag' => $senyera, 'label' => 'Català'], ]; $currentLang = $_SESSION['app_lang'] ?? 'fr'; foreach ($langs as $code => $lang): ?>

🧩 Modules actifs

Choisissez les modules visibles dans la navigation (partagé avec tous les membres de l'espace).

['icon' => '📅', 'label' => tr('menu_calendar')], 'budget' => ['icon' => '💰', 'label' => tr('menu_budget')], 'holidays' => ['icon' => '🏖️', 'label' => tr('menu_holidays')], 'gifts' => ['icon' => '🎁', 'label' => tr('menu_gifts')], 'garage' => ['icon' => '🚗', 'label' => tr('menu_garage')], 'memo' => ['icon' => '📝', 'label' => tr('menu_memo')], 'todo' => ['icon' => '✅', 'label' => tr('menu_todo')], 'calendar_ios' => ['icon' => '📱', 'label' => tr('menu_calendar_ios')], ]; ?>
$mod): $active = in_array($key, $enabledMods); ?>

📱 Intégration Calendrier iOS (CalDAV)

Configurez ici votre calendrier iCloud pour synchroniser les événements créés dans HouseHub.

Dernière synchro:

🖼️ Image d'accueil

Photo de fond affichée sur la page d'accueil (partagée avec tous les membres).

Fond actuel Image personnalisée

👤 Mon profil

🔒 Changer le mot de passe

🏠 Mon espace familial

Code d'invitation — partagez-le pour inviter quelqu'un

✓ Copié !

Lien d'inscription : /register.php

Membres ()

@ Admin