diff --git a/src/app/Packages/Features/Controller/FavoriteController.php b/src/app/Packages/Features/Controller/FavoriteController.php index 34561f3..10004a5 100644 --- a/src/app/Packages/Features/Controller/FavoriteController.php +++ b/src/app/Packages/Features/Controller/FavoriteController.php @@ -4,6 +4,7 @@ use App\Http\Controllers\Controller; use App\Packages\Features\CommandUseCases\UseCase\Favorite\AddFavoriteUseCase; +use App\Packages\Features\QueryUseCases\UseCase\Favorite\GetFavoriteHeritagesUseCase; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; @@ -11,6 +12,30 @@ class FavoriteController extends Controller { + public function getFavorites( + Request $request, + GetFavoriteHeritagesUseCase $useCase, + ): JsonResponse { + try { + $dtoCollection = $useCase->handle($request->user()->id); + + return response()->json([ + 'status' => 'success', + 'data' => $dtoCollection->toSummaryArray(), + ], 200); + } catch (Throwable $throwable) { + Log::error('Failed to get favorites', [ + 'message' => $throwable->getMessage(), + 'trace' => $throwable->getTraceAsString(), + ]); + + return response()->json([ + 'status' => 'error', + 'message' => 'Internal Server Error', + ], 500); + } + } + public function addFavorite( Request $request, AddFavoriteUseCase $useCase, diff --git a/src/app/Packages/Features/Tests/FavoriteControllerTest.php b/src/app/Packages/Features/Tests/FavoriteControllerTest.php index f734f4b..b9f6a76 100644 --- a/src/app/Packages/Features/Tests/FavoriteControllerTest.php +++ b/src/app/Packages/Features/Tests/FavoriteControllerTest.php @@ -5,7 +5,11 @@ use App\Models\User; use App\Models\WorldHeritage; use App\Packages\Domains\Favorite\Interface\FavoriteRepositoryInterface; +use App\Packages\Domains\WorldHeritage\Ports\Dto\HeritageSearchResult; +use App\Packages\Domains\WorldHeritage\Ports\WorldHeritageSearchPort; use App\Packages\Features\CommandUseCases\UseCase\Favorite\AddFavoriteUseCase; +use App\Packages\Features\QueryUseCases\QueryServiceInterface\WorldHeritageQueryServiceInterface; +use App\Packages\Features\QueryUseCases\UseCase\Favorite\GetFavoriteHeritagesUseCase; use Illuminate\Support\Facades\DB; use Mockery; use RuntimeException; @@ -17,6 +21,15 @@ protected function setUp(): void { parent::setUp(); $this->truncate(); + + $this->app->bind(WorldHeritageSearchPort::class, static function () { + return new class implements WorldHeritageSearchPort { + public function search($query, int $currentPage, int $perPage): HeritageSearchResult + { + return new HeritageSearchResult(ids: [], total: 0, currentPage: 1, perPage: $perPage, lastPage: 0); + } + }; + }); } protected function tearDown(): void @@ -110,4 +123,68 @@ public function test_addFavorite_returns_500_on_unexpected_error(): void 'message' => 'Internal Server Error', ]); } + + public function test_getFavorites_returns_200_with_favorite_heritages_when_authenticated(): void + { + $user = $this->seedUser(); + $worldHeritage1 = $this->seedWorldHeritage(1); + $worldHeritage2 = $this->seedWorldHeritage(2); + $token = $user->createToken('auth-token')->plainTextToken; + + $user->favorites()->attach($worldHeritage1->id); + $user->favorites()->attach($worldHeritage2->id); + + $response = $this->withToken($token)->getJson('/api/v1/favorites'); + + $response->assertStatus(200) + ->assertJsonFragment(['status' => 'success']) + ->assertJsonCount(2, 'data'); + + $ids = array_column($response->json('data'), 'id'); + $this->assertEqualsCanonicalizing([$worldHeritage1->id, $worldHeritage2->id], $ids); + } + + public function test_getFavorites_returns_200_with_empty_array_when_user_has_no_favorites(): void + { + $user = $this->seedUser(); + $token = $user->createToken('auth-token')->plainTextToken; + + $response = $this->withToken($token)->getJson('/api/v1/favorites'); + + $response->assertStatus(200) + ->assertJsonFragment(['status' => 'success']) + ->assertJsonCount(0, 'data'); + } + + public function test_getFavorites_returns_401_when_unauthenticated(): void + { + $response = $this->getJson('/api/v1/favorites'); + + $response->assertStatus(401); + } + + public function test_getFavorites_returns_500_on_unexpected_error(): void + { + $user = $this->seedUser(); + $token = $user->createToken('auth-token')->plainTextToken; + + $favoriteRepository = Mockery::mock(FavoriteRepositoryInterface::class); + $favoriteRepository->shouldReceive('getFavoriteWorldHeritageIds') + ->andThrow(new RuntimeException('Unexpected error')); + + $worldHeritageQueryService = Mockery::mock(WorldHeritageQueryServiceInterface::class); + + $this->app->instance( + GetFavoriteHeritagesUseCase::class, + new GetFavoriteHeritagesUseCase($favoriteRepository, $worldHeritageQueryService), + ); + + $response = $this->withToken($token)->getJson('/api/v1/favorites'); + + $response->assertStatus(500) + ->assertJsonFragment([ + 'status' => 'error', + 'message' => 'Internal Server Error', + ]); + } } diff --git a/src/routes/api.php b/src/routes/api.php index 73b2795..4c58d27 100644 --- a/src/routes/api.php +++ b/src/routes/api.php @@ -29,6 +29,7 @@ }); Route::controller(FavoriteController::class)->prefix('favorites')->middleware('auth:sanctum')->group(function (): void { + Route::get('/', 'getFavorites'); Route::post('/', 'addFavorite'); }); }); \ No newline at end of file