From 30f253b2d6e96a0c95ae9b96ca9bfd9ae044b7da Mon Sep 17 00:00:00 2001 From: Leon Date: Fri, 30 Jan 2026 12:08:17 +0100 Subject: [PATCH] feat: try fix meilisearch --- app/Http/Controllers/HuntsController.php | 63 ++++++++++-------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/app/Http/Controllers/HuntsController.php b/app/Http/Controllers/HuntsController.php index 36e4df4..ae74bd5 100644 --- a/app/Http/Controllers/HuntsController.php +++ b/app/Http/Controllers/HuntsController.php @@ -15,22 +15,16 @@ class HuntsController extends Controller { try { $searchTerm = $this->resolveSearchTerm($request); - - // Construire les filtres Meilisearch $filters = $this->buildMeilisearchFilters($request); - // Construire la recherche $search = Hunts::search($searchTerm ?? '') ->query(fn ($query) => $query->with('participants:id,avatar_uri')); - // N'ajouter le filter que s'il n'est pas vide + // ✅ IMPORTANT: n’envoie PAS filter s’il est vide if ($filters !== '') { - $search->options([ - 'filter' => $filters, - ]); + $search->options(['filter' => $filters]); } - // (utile en prod pour vérifier ce qui est réellement envoyé) Log::info('HUNTS_SEARCH', [ 'q' => $searchTerm ?? '', 'filters' => $filters, @@ -38,9 +32,7 @@ class HuntsController extends Controller 'index' => (new Hunts)->searchableAs(), ]); - $hunts = $search->paginate(10); - - return response()->json($hunts); + return response()->json($search->paginate(10)); } catch (\Throwable $e) { Log::error('Error fetching hunts: '.$e->getMessage()); @@ -63,13 +55,16 @@ class HuntsController extends Controller FILTER_NULL_ON_FAILURE ); - $userId = auth('sanctum')->id(); + $userId = auth('sanctum')->id(); // chez toi => UUID string if ($userId) { + $escapedUserId = $this->escapeMeiliString((string) $userId); + if ($participating === true) { - $filters[] = "participant_ids = {$userId}"; + // ✅ UUID => string + $filters[] = "participant_ids = \"{$escapedUserId}\""; } elseif ($participating === false) { - $filters[] = "participant_ids != {$userId}"; + $filters[] = "participant_ids != \"{$escapedUserId}\""; } } elseif ($participating === true) { $filters[] = "id < 0"; @@ -78,7 +73,7 @@ class HuntsController extends Controller // active if ($request->has('active')) { - $now = Carbon::now('UTC')->timestamp; // ✅ UTC + $now = Carbon::now('UTC')->timestamp; $active = filter_var($request->query('active'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); if ($active === true) { @@ -93,8 +88,7 @@ class HuntsController extends Controller if ($request->filled('city')) { $city = $request->query('city'); if (is_string($city)) { - // ✅ échapper correctement les quotes - $city = str_replace('"', '\"', $city); + $city = $this->escapeMeiliString($city); $filters[] = "city = \"{$city}\""; } } @@ -114,17 +108,20 @@ class HuntsController extends Controller )); if (!empty($validDifficulties)) { - $difficultyFilters = array_map(fn ($d) => "difficulty = \"{$d}\"", $validDifficulties); + $difficultyFilters = array_map( + fn ($d) => 'difficulty = "'.$this->escapeMeiliString($d).'"', + $validDifficulties + ); $filters[] = '(' . implode(' OR ', $difficultyFilters) . ')'; } } } - // ✅ Dates (UTC + end-of-day si nécessaire) + // dates (UTC) $startFrom = $this->parseDateFilterUtc($request->query('start_from')); - $startTo = $this->parseDateFilterUtc($request->query('start_to'), true); + $startTo = $this->parseDateFilterUtc($request->query('start_to')); $endFrom = $this->parseDateFilterUtc($request->query('end_from')); - $endTo = $this->parseDateFilterUtc($request->query('end_to'), true); + $endTo = $this->parseDateFilterUtc($request->query('end_to')); if ($startFrom) { $filters[] = "start_at_timestamp >= {$startFrom->timestamp}"; @@ -155,29 +152,23 @@ class HuntsController extends Controller return $searchTerm !== '' ? $searchTerm : null; } - /** - * Parse une date en UTC. - * Si $endOfDay=true et que l'entrée ressemble à une date "YYYY-MM-DD", - * on la transforme en fin de journée UTC. - */ - private function parseDateFilterUtc(mixed $value, bool $endOfDay = false): ?Carbon + private function parseDateFilterUtc(mixed $value): ?Carbon { if (!is_string($value) || trim($value) === '') { return null; } try { - $value = trim($value); - - // Si le front envoie une date simple "2026-01-30" - if ($endOfDay && preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { - return Carbon::createFromFormat('Y-m-d', $value, 'UTC')->endOfDay(); - } - - // ISO 8601 type "2026-01-29T23:00:00.000Z" => UTC garanti - return Carbon::parse($value)->utc(); + return Carbon::parse(trim($value))->utc(); } catch (\Throwable $e) { return null; } } + + private function escapeMeiliString(string $value): string + { + // Échappe les backslashes et les guillemets pour une string Meilisearch + $value = str_replace('\\', '\\\\', $value); + return str_replace('"', '\"', $value); + } }