diff --git a/app/Http/Controllers/Api/ApiV2Controller.php b/app/Http/Controllers/Api/ApiV2Controller.php index f4c821f1a..2acec2e13 100644 --- a/app/Http/Controllers/Api/ApiV2Controller.php +++ b/app/Http/Controllers/Api/ApiV2Controller.php @@ -297,9 +297,8 @@ class ApiV2Controller extends BasePageController UserRequest::addApiRequest($user->id, $request->getRequestUri()); event(new UserAccessedApi($user, $request->ip())); - $q = (string) $request->input('id', ''); - if ($q === '') { - return response()->json(['error' => 'Missing id (search query)'], 400); + if ($request->has('id') && $request->isNotFilled('id')) { + return response()->json(['error' => 'Incorrect parameter (id must not be empty)'], 400); } $offset = $this->api->offset($request); @@ -318,17 +317,35 @@ class ApiV2Controller extends BasePageController $catExclusions = User::getCategoryExclusionById($user->id); $groupName = $this->api->group($request); - $relData = $this->releaseSearchService->apiMusicSearch( - $q, - $groupName, - $offset, - $limit, - $maxAge, - $catExclusions, - $categoryID, - $minSize, - $sort - ); + if (! $request->filled('id')) { + if ($categoryID === [-1]) { + $categoryID = [Category::MUSIC_ROOT]; + } + + $relData = $this->releaseBrowseService->getBrowseRangeForApi( + 1, + $categoryID, + $offset, + $limit, + $sort, + $maxAge, + $catExclusions, + $groupName, + $minSize + ); + } else { + $relData = $this->releaseSearchService->apiMusicSearch( + (string) $request->input('id'), + $groupName, + $offset, + $limit, + $maxAge, + $catExclusions, + $categoryID, + $minSize, + $sort + ); + } return $this->buildSearchResponse($relData, $user); } @@ -343,9 +360,8 @@ class ApiV2Controller extends BasePageController UserRequest::addApiRequest($user->id, $request->getRequestUri()); event(new UserAccessedApi($user, $request->ip())); - $q = (string) $request->input('id', ''); - if ($q === '') { - return response()->json(['error' => 'Missing id (search query)'], 400); + if ($request->has('id') && $request->isNotFilled('id')) { + return response()->json(['error' => 'Incorrect parameter (id must not be empty)'], 400); } $offset = $this->api->offset($request); @@ -364,17 +380,35 @@ class ApiV2Controller extends BasePageController $catExclusions = User::getCategoryExclusionById($user->id); $groupName = $this->api->group($request); - $relData = $this->releaseSearchService->apiBookSearch( - $q, - $groupName, - $offset, - $limit, - $maxAge, - $catExclusions, - $categoryID, - $minSize, - $sort - ); + if (! $request->filled('id')) { + if ($categoryID === [-1]) { + $categoryID = [Category::BOOKS_ROOT]; + } + + $relData = $this->releaseBrowseService->getBrowseRangeForApi( + 1, + $categoryID, + $offset, + $limit, + $sort, + $maxAge, + $catExclusions, + $groupName, + $minSize + ); + } else { + $relData = $this->releaseSearchService->apiBookSearch( + (string) $request->input('id'), + $groupName, + $offset, + $limit, + $maxAge, + $catExclusions, + $categoryID, + $minSize, + $sort + ); + } return $this->buildSearchResponse($relData, $user); } diff --git a/tests/Feature/ApiRequestMatrixTest.php b/tests/Feature/ApiRequestMatrixTest.php index 39a3485d2..10e4389e5 100644 --- a/tests/Feature/ApiRequestMatrixTest.php +++ b/tests/Feature/ApiRequestMatrixTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Tests\Feature; use App\Http\Controllers\Api\ApiController; +use App\Http\Controllers\Api\ApiV2Controller; use App\Models\Category; use App\Services\Releases\ReleaseBrowseService; use App\Services\Releases\ReleaseSearchService; @@ -347,6 +348,111 @@ class ApiRequestMatrixTest extends TestCase } } + public function test_v2_audio_without_id_browses_requested_categories(): void + { + $token = (string) DB::table('users')->value('api_token'); + $request = Request::create('/api/v2/audio', 'GET', [ + 'cat' => '3000,3010,3020,3030,3040,3050,3060,3999', + 'api_token' => $token, + ]); + + $releaseSearchService = Mockery::mock(ReleaseSearchService::class); + $releaseSearchService->shouldNotReceive('apiMusicSearch'); + $releaseBrowseService = Mockery::mock(ReleaseBrowseService::class); + $releaseBrowseService->shouldReceive('getBrowseRangeForApi') + ->once() + ->with( + 1, + ['3000', '3010', '3020', '3030', '3040', '3050', '3060', '3999'], + 0, + 100, + 'posted_desc', + -1, + [5030], + -1, + 0 + ) + ->andReturn(collect()); + + $controller = new ApiV2Controller(app(ApiController::class), $releaseSearchService, $releaseBrowseService); + + $response = $controller->audio($request); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame([], $response->getData(true)['results']); + } + + public function test_v2_books_without_id_browses_requested_categories(): void + { + $token = (string) DB::table('users')->value('api_token'); + $request = Request::create('/api/v2/books', 'GET', [ + 'cat' => '3030,7020,8010', + 'api_token' => $token, + ]); + + $releaseSearchService = Mockery::mock(ReleaseSearchService::class); + $releaseSearchService->shouldNotReceive('apiBookSearch'); + $releaseBrowseService = Mockery::mock(ReleaseBrowseService::class); + $releaseBrowseService->shouldReceive('getBrowseRangeForApi') + ->once() + ->with( + 1, + ['3030', '7020', '8010'], + 0, + 100, + 'posted_desc', + -1, + [5030], + -1, + 0 + ) + ->andReturn(collect()); + + $controller = new ApiV2Controller(app(ApiController::class), $releaseSearchService, $releaseBrowseService); + + $response = $controller->books($request); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame([], $response->getData(true)['results']); + } + + public function test_v2_audio_and_books_without_id_default_to_their_root_categories(): void + { + $token = (string) DB::table('users')->value('api_token'); + + foreach ([ + 'audio' => ['method' => 'audio', 'category' => [Category::MUSIC_ROOT]], + 'books' => ['method' => 'books', 'category' => [Category::BOOKS_ROOT]], + ] as $endpoint => $expectation) { + $request = Request::create('/api/v2/'.$endpoint, 'GET', [ + 'api_token' => $token, + ]); + + $releaseSearchService = Mockery::mock(ReleaseSearchService::class); + $releaseBrowseService = Mockery::mock(ReleaseBrowseService::class); + $releaseBrowseService->shouldReceive('getBrowseRangeForApi') + ->once() + ->with( + 1, + $expectation['category'], + 0, + 100, + 'posted_desc', + -1, + [5030], + -1, + 0 + ) + ->andReturn(collect()); + + $controller = new ApiV2Controller(app(ApiController::class), $releaseSearchService, $releaseBrowseService); + $response = $controller->{$expectation['method']}($request); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame([], $response->getData(true)['results']); + } + } + public function test_v2_movie_requires_query_or_external_id(): void { $token = (string) DB::table('users')->value('api_token');