From f752c28d99049a244acd0bb8e8d4df4e81711aaf Mon Sep 17 00:00:00 2001 From: Leon Morival Date: Fri, 14 Aug 2026 14:17:29 +0200 Subject: [PATCH] feat: followers and following --- app/Http/Resources/FollowResource.php | 4 ++ tests/Feature/FollowListingTest.php | 64 +++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/Feature/FollowListingTest.php diff --git a/app/Http/Resources/FollowResource.php b/app/Http/Resources/FollowResource.php index daa3fce..2af4741 100644 --- a/app/Http/Resources/FollowResource.php +++ b/app/Http/Resources/FollowResource.php @@ -2,10 +2,12 @@ namespace App\Http\Resources; +use App\Models\User; use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; use Illuminate\Support\Facades\Storage; +/** @mixin User */ class FollowResource extends JsonResource { /** @@ -18,7 +20,9 @@ class FollowResource extends JsonResource return [ 'id' => $this->id, 'name' => $this->name, + 'bio' => $this->bio, 'avatarUrl' => $this->avatar_url ? asset(Storage::url($this->avatar_url)) : null, + 'accountVerified' => $this->account_verified_at !== null, ]; } } diff --git a/tests/Feature/FollowListingTest.php b/tests/Feature/FollowListingTest.php new file mode 100644 index 0000000..c1e03a3 --- /dev/null +++ b/tests/Feature/FollowListingTest.php @@ -0,0 +1,64 @@ +create(); + $acceptedFollower = User::factory()->create([ + 'account_verified_at' => now(), + 'bio' => 'Cuisine équilibrée.', + ]); + $pendingFollower = User::factory()->create(); + + $acceptedFollower->following()->attach($user, ['status' => FollowStatus::Accepted]); + $pendingFollower->following()->attach($user, ['status' => FollowStatus::Pending]); + + Sanctum::actingAs($user); + + $this->getJson("/api/users/{$user->id}/followers?per_page=10") + ->assertOk() + ->assertJsonCount(1, 'data') + ->assertJsonPath('data.0.id', $acceptedFollower->id) + ->assertJsonPath('data.0.bio', 'Cuisine équilibrée.') + ->assertJsonPath('data.0.accountVerified', true) + ->assertJsonPath('meta.total', 1) + ->assertJsonMissing(['id' => $pendingFollower->id]); +}); + +it('lists only accepted followed accounts and exposes the pagination total', function () { + $user = User::factory()->create(); + $accepted = User::factory()->count(3)->create(); + $pending = User::factory()->create(); + + $accepted->each( + fn (User $followed): mixed => $user->following()->attach( + $followed, + ['status' => FollowStatus::Accepted], + ), + ); + $user->following()->attach($pending, ['status' => FollowStatus::Pending]); + + Sanctum::actingAs($user); + + $this->getJson("/api/users/{$user->id}/following?per_page=2") + ->assertOk() + ->assertJsonCount(2, 'data') + ->assertJsonPath('meta.total', 3) + ->assertJsonPath('meta.per_page', 2) + ->assertJsonMissing(['id' => $pending->id]); +}); + +it('does not expose another users social lists', function () { + $user = User::factory()->create(); + $otherUser = User::factory()->create(); + + Sanctum::actingAs($user); + + $this->getJson("/api/users/{$otherUser->id}/followers")->assertForbidden(); + $this->getJson("/api/users/{$otherUser->id}/following")->assertForbidden(); +});