From 324087945c1d621bfcee9f6d87ac70cae295951f Mon Sep 17 00:00:00 2001 From: Houssem Eddine BENABDALLAH Date: Fri, 30 Oct 2026 12:48:02 +0100 Subject: [PATCH 1/2] fix: find organizations in the API whatever the handle's case --- .../ListApiOrganizationMentionsRequest.php | 9 +++++++-- app/Http/Requests/ShowApiOrganizationRequest.php | 9 +++++++-- .../Api/OrganizationControllerTest.php | 15 +++++++++++++++ .../Api/OrganizationMentionControllerTest.php | 10 ++++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/app/Http/Requests/ListApiOrganizationMentionsRequest.php b/app/Http/Requests/ListApiOrganizationMentionsRequest.php index ac427ab19..d81c00f60 100644 --- a/app/Http/Requests/ListApiOrganizationMentionsRequest.php +++ b/app/Http/Requests/ListApiOrganizationMentionsRequest.php @@ -26,7 +26,8 @@ public function rules(): array } /** - * Only organizations that already have a page, so looking one up never asks GitHub. + * Only organizations that already have a page, so looking one up never asks GitHub. Like their web page, whatever + * the handle's case, the exact case first. */ public function organization(): ?Organization { @@ -34,7 +35,11 @@ public function organization(): ?Organization assert(is_string($handle)); return $this->organization ??= Organization::query() - ->whereRelation('profile', 'handle', $handle) + ->select('organizations.*') + ->join('profiles', 'profiles.id', '=', 'organizations.id') + ->whereRaw('LOWER(profiles.handle) = LOWER(?)', [$handle]) + ->orderByRaw('profiles.handle = ? desc', [$handle]) + ->orderBy('profiles.handle') ->first(); } } diff --git a/app/Http/Requests/ShowApiOrganizationRequest.php b/app/Http/Requests/ShowApiOrganizationRequest.php index 670e9ed24..8af02b67d 100644 --- a/app/Http/Requests/ShowApiOrganizationRequest.php +++ b/app/Http/Requests/ShowApiOrganizationRequest.php @@ -26,7 +26,8 @@ public function rules(): array } /** - * Only organizations that already have a page, so looking one up never asks GitHub. + * Only organizations that already have a page, so looking one up never asks GitHub. Like their web page, whatever + * the handle's case, the exact case first. */ public function organization(): ?Organization { @@ -34,7 +35,11 @@ public function organization(): ?Organization assert(is_string($handle)); return $this->organization ??= Organization::query() - ->whereRelation('profile', 'handle', $handle) + ->select('organizations.*') + ->join('profiles', 'profiles.id', '=', 'organizations.id') + ->whereRaw('LOWER(profiles.handle) = LOWER(?)', [$handle]) + ->orderByRaw('profiles.handle = ? desc', [$handle]) + ->orderBy('profiles.handle') ->first(); } } diff --git a/tests/Feature/Controllers/Api/OrganizationControllerTest.php b/tests/Feature/Controllers/Api/OrganizationControllerTest.php index 0a8cbe483..2238630c1 100644 --- a/tests/Feature/Controllers/Api/OrganizationControllerTest.php +++ b/tests/Feature/Controllers/Api/OrganizationControllerTest.php @@ -35,3 +35,18 @@ $this->getJson('/api/v1/organizations/octocat')->assertNotFound(); $this->getJson('/api/v1/organizations/missing')->assertNotFound(); }); + +it('shows an organization whatever the handle\'s case', function (): void { + Organization::factory()->create(['handle' => 'Laravel']); + + $this->getJson('/api/v1/organizations/laravel')->assertOk()->assertJsonPath('data.handle', 'Laravel'); + $this->getJson('/api/v1/organizations/LARAVEL')->assertOk()->assertJsonPath('data.handle', 'Laravel'); +}); + +it('shows the organization in the exact case when a stale one holds the handle in another case', function (): void { + Organization::factory()->create(['handle' => 'laravel', 'name' => 'Lower']); + Organization::factory()->create(['handle' => 'Laravel', 'name' => 'Mixed']); + + $this->getJson('/api/v1/organizations/laravel')->assertOk()->assertJsonPath('data.name', 'Lower'); + $this->getJson('/api/v1/organizations/Laravel')->assertOk()->assertJsonPath('data.name', 'Mixed'); +}); diff --git a/tests/Feature/Controllers/Api/OrganizationMentionControllerTest.php b/tests/Feature/Controllers/Api/OrganizationMentionControllerTest.php index 1cd4304e9..54d0064a6 100644 --- a/tests/Feature/Controllers/Api/OrganizationMentionControllerTest.php +++ b/tests/Feature/Controllers/Api/OrganizationMentionControllerTest.php @@ -52,3 +52,13 @@ $this->getJson('/api/v1/organizations/octocat/mentions')->assertNotFound(); }); + +it('lists the mentions of an organization whatever the handle\'s case', function (): void { + $laravel = Organization::factory()->create(['handle' => 'Laravel']); + $commit = Commit::factory()->create(['body' => 'Thanks @laravel']); + resolve(CreateCommitTopics::class)->handle($commit, ['Laravel' => $laravel->id]); + + $this->getJson('/api/v1/organizations/laravel/mentions') + ->assertOk() + ->assertJsonPath('data.*.id', [$commit->id]); +}); From b3bbc2288b4957d49d1470b768d8a24b45ef6638 Mon Sep 17 00:00:00 2001 From: Houssem Eddine BENABDALLAH Date: Fri, 30 Oct 2026 12:55:40 +0100 Subject: [PATCH 2/2] test: cover the exact case first on the organization mentions endpoint --- .../Api/OrganizationMentionControllerTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/Feature/Controllers/Api/OrganizationMentionControllerTest.php b/tests/Feature/Controllers/Api/OrganizationMentionControllerTest.php index 54d0064a6..3c47fdf7f 100644 --- a/tests/Feature/Controllers/Api/OrganizationMentionControllerTest.php +++ b/tests/Feature/Controllers/Api/OrganizationMentionControllerTest.php @@ -62,3 +62,15 @@ ->assertOk() ->assertJsonPath('data.*.id', [$commit->id]); }); + +it('lists the mentions of the organization in the exact case when a stale one holds the handle in another case', function (): void { + $lower = Organization::factory()->create(['handle' => 'laravel']); + $mixed = Organization::factory()->create(['handle' => 'Laravel']); + $lowerCommit = Commit::factory()->create(['body' => 'Thanks @laravel']); + $mixedCommit = Commit::factory()->create(['body' => 'Thanks @Laravel']); + resolve(CreateCommitTopics::class)->handle($lowerCommit, ['laravel' => $lower->id]); + resolve(CreateCommitTopics::class)->handle($mixedCommit, ['Laravel' => $mixed->id]); + + $this->getJson('/api/v1/organizations/laravel/mentions')->assertOk()->assertJsonPath('data.*.id', [$lowerCommit->id]); + $this->getJson('/api/v1/organizations/Laravel/mentions')->assertOk()->assertJsonPath('data.*.id', [$mixedCommit->id]); +});