This commit is contained in:
2026-05-27 11:44:10 -04:00
commit 414f85ad05
31452 changed files with 3580409 additions and 0 deletions

View File

@ -0,0 +1,311 @@
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class DebugGcal extends CI_Controller
{
public function index()
{
$email = $this->input->get('email', true) ?: '';
$dateYmd = $this->input->get('date', true) ?: date('Y-m-d');
$tz = $this->input->get('tz', true) ?: 'America/Toronto';
$base = $this->input->get('base', true) ?: '08:00';
$dur = (int)($this->input->get('dur', true) ?: 1);
$calId = $this->input->get('calendar', true) ?: 'primary';
header('Content-Type: text/html; charset=utf-8');
echo "<h1>Debug GCal Test de placement</h1>";
echo "<h2>Paramètres</h2><pre>";
echo "email : $email\n";
echo "date : $dateYmd\n";
echo "timezone : $tz\n";
echo "base : $base\n";
echo "dur(min) : $dur\n";
echo "calendar : $calId\n";
echo "</pre>";
if (empty($email)) {
echo "<p style='color:red'>⚠️ Fournis ?email=user@domaine.com dans lURL.</p>";
$this->print_usage(); return;
}
// Fenêtre de la journée
try { $tzObj = new DateTimeZone($tz); } catch (Exception $e) { $tzObj = new DateTimeZone('America/Toronto'); }
$dayStart = new DateTime("$dateYmd 00:00:00", $tzObj);
$dayEnd = new DateTime("$dateYmd 23:59:59", $tzObj);
// Charge la lib telle quen prod
$this->load->library('GCalService');
echo "<h2>Librairie GCalService</h2><pre>";
echo "Class: " . get_class($this->gcalservice) . "\n";
echo "Méthodes disponibles:\n";
echo " - freeBusy : " . (method_exists($this->gcalservice, 'freeBusy') ? 'OUI' : 'non') . "\n";
echo " - listEvents : " . (method_exists($this->gcalservice, 'listEvents') ? 'OUI' : 'non') . "\n";
echo "Classes Google connues:\n";
echo " - Google_Service_Calendar: " . (class_exists('Google_Service_Calendar') ? 'OUI' : 'non') . "\n";
echo " - Google_Client : " . (class_exists('Google_Client') ? 'OUI' : 'non') . "\n";
echo "</pre>";
// ===== Introspection des propriétés de la librairie =====
$props = get_object_vars($this->gcalservice);
echo "<h2>Propriétés de GCalService</h2>";
if (empty($props)) {
echo "<pre>(aucune propriété publique/protégée visible)</pre>";
} else {
echo "<table border='1' cellspacing='0' cellpadding='4'><tr><th>Nom</th><th>Type</th><th>Détail</th></tr>";
foreach ($props as $k => $v) {
$type = gettype($v);
$detail = '';
if (is_object($v)) {
$cls = get_class($v);
$type = "object";
$detail = $cls;
} elseif (is_array($v)) {
$detail = 'array('.count($v).')';
} else {
$detail = htmlspecialchars(var_export($v, true));
}
echo "<tr><td>".htmlspecialchars($k)."</td><td>$type</td><td>".htmlspecialchars($detail)."</td></tr>";
}
echo "</table>";
}
// Tente de découvrir un service Calendar déjà initialisé
$calendarService = null;
$googleClient = null;
// 1) Cherche un objet déjà de type Google_Service_Calendar
foreach ($props as $v) {
if (is_object($v) && class_exists('Google_Service_Calendar') && $v instanceof Google_Service_Calendar) {
$calendarService = $v; break;
}
}
// 2) Sinon, cherche un Google_Client
if (!$calendarService && class_exists('Google_Client')) {
foreach ($props as $v) {
if (is_object($v) && $v instanceof Google_Client) {
$googleClient = $v; break;
}
}
}
// 3) Sinon, si la lib expose une méthode getClient(), on lessaie
if (!$calendarService && !$googleClient && method_exists($this->gcalservice, 'getClient')) {
try {
$maybeClient = $this->gcalservice->getClient(); // sans effet de bord
if (is_object($maybeClient) && class_exists('Google_Client') && $maybeClient instanceof Google_Client) {
$googleClient = $maybeClient;
}
} catch (Exception $e) {
echo "<p style='color:red'><b>getClient()</b> a levé: ".htmlspecialchars($e->getMessage())."</p>";
}
}
// 4) Fabrique un service si on a un client
if (!$calendarService && $googleClient && class_exists('Google_Service_Calendar')) {
$calendarService = new Google_Service_Calendar($googleClient);
}
echo "<h2>Détection de service</h2><pre>";
echo "calendarService: ".($calendarService ? ('OK ('.get_class($calendarService).')') : 'non')."\n";
echo "googleClient : ".($googleClient ? ('OK ('.get_class($googleClient).')') : 'non')."\n";
echo "</pre>";
// ==== Appels en lecture en utilisant, si possible, le service détecté ====
$busyIntervals = [];
$events = [];
// FreeBusy via service direct (si dispo)
if ($calendarService && method_exists($calendarService->freebusy, 'query')) {
echo "<h2>freeBusy() via service détecté</h2>";
try {
$fbReq = new Google_Service_Calendar_FreeBusyRequest();
$fbReq->setTimeMin($dayStart->format(DateTime::RFC3339));
$fbReq->setTimeMax($dayEnd->format(DateTime::RFC3339));
$fbReq->setTimeZone($tz);
$item = new Google_Service_Calendar_FreeBusyRequestItem();
$item->setId($calId);
$fbReq->setItems([$item]);
$resp = $calendarService->freebusy->query($fbReq);
$cals = $resp->getCalendars();
if (isset($cals[$calId])) {
$blocks = $cals[$calId]['busy'] ?? [];
foreach ($blocks as $b) {
$s = new DateTime($b['start']);
$e = new DateTime($b['end']);
$s->setTimezone($tzObj);
$e->setTimezone($tzObj);
$busyIntervals[] = [$s, $e];
}
}
if (empty($busyIntervals)) echo "<p><i>(aucun busy remonté)</i></p>";
$this->print_busy($busyIntervals, $tzObj);
} catch (Exception $e) {
echo "<pre style='color:red'>Exception: ".htmlspecialchars($e->getMessage())."</pre>";
}
} else {
echo "<h2>freeBusy() via service détecté</h2><p><i>service indisponible</i></p>";
}
// listEvents via service direct (si dispo)
if ($calendarService && method_exists($calendarService->events, 'listEvents')) {
echo "<h2>listEvents() via service détecté</h2>";
try {
$opt = [
'timeMin' => $dayStart->format(DateTime::RFC3339),
'timeMax' => $dayEnd->format(DateTime::RFC3339),
'singleEvents' => true,
'orderBy' => 'startTime',
'maxResults' => 2500,
];
$resp = $calendarService->events->listEvents($calId, $opt);
foreach ($resp->getItems() as $ev) {
$start = $ev->getStart();
$end = $ev->getEnd();
$events[] = [
'start' => [
'dateTime' => $start ? $start->getDateTime() : null,
'date' => $start ? $start->getDate() : null,
],
'end' => [
'dateTime' => $end ? $end->getDateTime() : null,
'date' => $end ? $end->getDate() : null,
],
];
}
if (empty($events)) echo "<p><i>(aucun événement)</i></p>";
$this->print_events($events, $tzObj);
} catch (Exception $e) {
echo "<pre style='color:red'>Exception: ".htmlspecialchars($e->getMessage())."</pre>";
}
} else {
echo "<h2>listEvents() via service détecté</h2><p><i>service indisponible</i></p>";
}
// Si rien via service, on retombe sur tes méthodes existantes (si présentes) pour comparer
if (empty($busyIntervals) && method_exists($this->gcalservice, 'freeBusy')) {
echo "<h2>freeBusy() via librairie</h2>";
try {
$busyLib = $this->gcalservice->freeBusy($email, $calId, $dayStart->format(DateTime::RFC3339), $dayEnd->format(DateTime::RFC3339), $tz);
if (is_array($busyLib)) {
// On accepte deux formats: paires [DateTime, DateTime] ou tableaux ['start'=>..., 'end'=>...]
foreach ($busyLib as $pair) {
if (is_array($pair) && count($pair) === 2 && $pair[0] instanceof DateTime) {
$s = $pair[0]; $e = $pair[1];
} else {
$s = isset($pair['start']) ? new DateTime($pair['start']) : null;
$e = isset($pair['end']) ? new DateTime($pair['end']) : null;
}
if ($s && $e) {
$s->setTimezone($tzObj);
$e->setTimezone($tzObj);
$busyIntervals[] = [$s, $e];
}
}
if (empty($busyIntervals)) echo "<p><i>(aucun busy via librairie)</i></p>";
$this->print_busy($busyIntervals, $tzObj);
}
} catch (Exception $e) {
echo "<pre style='color:red'>Exception: ".htmlspecialchars($e->getMessage())."</pre>";
}
}
if (empty($events) && method_exists($this->gcalservice, 'listEvents')) {
echo "<h2>listEvents() via librairie</h2>";
try {
$events = $this->gcalservice->listEvents($email, $calId, $dayStart->format(DateTime::RFC3339), $dayEnd->format(DateTime::RFC3339));
$this->print_events($events, $tzObj);
} catch (Exception $e) {
echo "<pre style='color:red'>Exception: ".htmlspecialchars($e->getMessage())."</pre>";
}
}
// Normalisation finale des intervals occupés
echo "<h2>Busy normalisés (utilisés pour la simulation)</h2>";
$normBusy = [];
foreach ($busyIntervals as $pair) {
if (!is_array($pair) || count($pair) !== 2) continue;
$s = $pair[0]; $e = $pair[1];
if (!($s instanceof DateTime) || !($e instanceof DateTime)) continue;
$normBusy[] = [$s, $e];
}
$this->print_busy($normBusy, $tzObj);
// Simulation locale (ne crée rien)
$slot = $this->simulate_slot($normBusy, $dateYmd, $tzObj, $base, $dur);
echo "<h2>Simulation de placement</h2><pre>";
echo "Candidat retenu : " . $slot['startIso'] . "" . $slot['endIso'] . "\n";
echo "</pre>";
$this->print_usage();
}
private function print_busy(array $busy, DateTimeZone $tzObj)
{
if (empty($busy)) { echo "<pre>(aucun)</pre>"; return; }
echo "<table border='1' cellpadding='4' cellspacing='0'>";
echo "<tr><th>#</th><th>Start (".$tzObj->getName().")</th><th>End (".$tzObj->getName().")</th><th>Durée (min)</th></tr>";
$i = 1;
foreach ($busy as $pair) {
$s = $pair[0]; $e = $pair[1];
$mins = round(($e->getTimestamp() - $s->getTimestamp()) / 60);
echo "<tr><td>".$i++."</td><td>".$s->format('Y-m-d H:i:s')."</td><td>".$e->format('Y-m-d H:i:s')."</td><td style='text-align:right'>".$mins."</td></tr>";
}
echo "</table>";
}
private function print_events(array $events, DateTimeZone $tzObj)
{
if (empty($events)) { echo "<pre>(aucun)</pre>"; return; }
echo "<table border='1' cellpadding='4' cellspacing='0'>";
echo "<tr><th>#</th><th>start.dateTime</th><th>start.date</th><th>end.dateTime</th><th>end.date</th></tr>";
$i = 1;
foreach ($events as $ev) {
$sdt = $ev['start']['dateTime'] ?? '';
$sd = $ev['start']['date'] ?? '';
$edt = $ev['end']['dateTime'] ?? '';
$ed = $ev['end']['date'] ?? '';
echo "<tr><td>".$i++."</td><td>".htmlspecialchars($sdt)."</td><td>".htmlspecialchars($sd)."</td><td>".htmlspecialchars($edt)."</td><td>".htmlspecialchars($ed)."</td></tr>";
}
echo "</table>";
}
private function simulate_slot(array $busyIntervals, string $dateYmd, DateTimeZone $tzObj, string $baseTime, int $durationMin): array
{
$candidate = new DateTime("$dateYmd $baseTime:00", $tzObj);
$dayEnd = new DateTime("$dateYmd 23:59:59", $tzObj);
usort($busyIntervals, function($a,$b){ return $a[0] <=> $b[0]; });
for ($i=0; $i<1440; $i++) {
if ($candidate > $dayEnd) break;
$candEnd = (clone $candidate)->modify("+$durationMin minutes");
$conflict = false;
foreach ($busyIntervals as $pair) {
$bs = $pair[0]; $be = $pair[1];
if ($candidate < $be && $candEnd > $bs) { $conflict = true; break; }
}
if (!$conflict) {
return [
'startIso' => $candidate->format(DateTime::RFC3339),
'endIso' => $candEnd->format(DateTime::RFC3339),
];
}
$candidate->modify('+1 minute');
}
$fallbackStart = new DateTime("$dateYmd $baseTime:00", $tzObj);
$fallbackEnd = (clone $fallbackStart)->modify("+$durationMin minutes");
return [
'startIso' => $fallbackStart->format(DateTime::RFC3339),
'endIso' => $fallbackEnd->format(DateTime::RFC3339),
];
}
private function print_usage()
{
echo "<h2>Usage</h2><pre>";
echo "GET /index.php/debug-gcal?email=prenom.nom@domaine.com&date=2025-09-23&tz=America/Toronto&base=08:00&dur=1&calendar=primary\n";
echo "</pre>";
}
}