diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index bf7edc75514e..614ad9b37244 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -3,37 +3,38 @@ namespace App\Http\Controllers\Api; use App\Events\CheckoutableCheckedIn; -use App\Http\Requests\StoreAssetRequest; -use App\Http\Requests\UpdateAssetRequest; -use App\Http\Traits\MigratesLegacyAssetLocations; -use App\Http\Transformers\ComponentsTransformer; -use App\Models\AccessoryCheckout; -use App\Models\CheckoutAcceptance; -use App\Models\LicenseSeat; -use Illuminate\Database\Eloquent\Builder; -use Illuminate\Http\JsonResponse; -use Illuminate\Support\Facades\Crypt; -use Illuminate\Support\Facades\Gate; use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Http\Requests\AssetCheckoutRequest; +use App\Http\Requests\FilterRequest; +use App\Http\Requests\StoreAssetRequest; +use App\Http\Requests\UpdateAssetRequest; +use App\Http\Traits\MigratesLegacyAssetLocations; use App\Http\Transformers\AssetsTransformer; +use App\Http\Transformers\ComponentsTransformer; use App\Http\Transformers\LicensesTransformer; use App\Http\Transformers\SelectlistTransformer; +use App\Models\AccessoryCheckout; use App\Models\Asset; use App\Models\AssetModel; +use App\Models\CheckoutAcceptance; use App\Models\Company; use App\Models\CustomField; use App\Models\License; +use App\Models\LicenseSeat; use App\Models\Location; use App\Models\Setting; use App\Models\User; +use App\View\Label; use Carbon\Carbon; -use Illuminate\Support\Facades\DB; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Crypt; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Route; -use App\View\Label; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Validator; @@ -56,7 +57,7 @@ class AssetsController extends Controller * @param int $assetId * @since [v4.0] */ - public function index(Request $request, $action = null, $upcoming_status = null) : JsonResponse | array + public function index(FilterRequest $request, $action = null, $upcoming_status = null) : JsonResponse | array { diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 0e13ba44c446..4d1c052915ba 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -31,6 +31,7 @@ use Illuminate\Support\Facades\Log; use App\Http\Requests\DeleteUserRequest; use Illuminate\Http\JsonResponse; +use App\Http\Requests\FilterRequest; class UsersController extends Controller { @@ -42,7 +43,7 @@ class UsersController extends Controller * * @return array */ - public function index(Request $request) : array + public function index(FilterRequest $request) : array { $this->authorize('view', User::class); diff --git a/app/Http/Requests/FilterRequest.php b/app/Http/Requests/FilterRequest.php new file mode 100644 index 000000000000..d22e58b08989 --- /dev/null +++ b/app/Http/Requests/FilterRequest.php @@ -0,0 +1,29 @@ +|string> + */ + public function rules(): array + { + return [ + 'filter' => ['nullable', new ValidJson()], + ]; + } +} diff --git a/app/Rules/ValidJson.php b/app/Rules/ValidJson.php new file mode 100644 index 000000000000..7923494a0a4b --- /dev/null +++ b/app/Rules/ValidJson.php @@ -0,0 +1,21 @@ +assertResponseDoesNotContainInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); } + + public function test_gracefully_handles_malformed_filter() + { + $this->actingAsForApi(User::factory()->viewAssets()->create()) + ->getJson(route('api.assets.index', [ + // filter should be a json encoded array and not a string + 'filter' => 'asset_tag:12345', + ])) + ->assertStatusMessageIs('error') + ->assertJson(function (AssertableJson $json) { + $json->has('messages.filter')->etc(); + }); + } + + public function testReturnsResultViaFilter() + { + + Asset::factory()->count(3)->create(['name' => 'MY AWESOME ASSET NAME']); + $this->actingAsForApi(User::factory()->viewAssets()->create()) + ->getJson(route('api.assets.index', [ + 'filter' => '{"name":"MY AWESOME ASSET NAME"}', + ])) + ->assertOk() + ->assertJsonStructure([ + 'total', + 'rows', + ]) + ->assertJson(fn(AssertableJson $json) => $json->has('rows', 3)->etc()); + } } diff --git a/tests/Feature/Users/Api/IndexUsersTest.php b/tests/Feature/Users/Api/IndexUsersTest.php index 00a7423cf0bf..cd6dfdd88e24 100644 --- a/tests/Feature/Users/Api/IndexUsersTest.php +++ b/tests/Feature/Users/Api/IndexUsersTest.php @@ -65,6 +65,36 @@ public function test_gracefully_handles_malformed_filter() // filter should be a json encoded array and not a string 'filter' => 'email:an-email-address@example.com', ])) - ->assertOk(); + ->assertStatusMessageIs('error') + ->assertJson(function (AssertableJson $json) { + $json->has('messages.filter')->etc(); + }); + } + + public function testReturnsResultViaFilter() + { + + User::factory()->count(3)->create(['first_name' => 'Awesome', 'last_name' => 'Admin', 'email' => 'awesome@example.org']); + $this->actingAsForApi(User::factory()->viewUsers()->create()) + ->getJson(route('api.users.index', [ + 'filter' => '{"first_name":"Awesome","last_name":"Admin","email":"awesome@example.org"}', + ])) + ->assertOk() + ->assertJsonStructure([ + 'total', + 'rows', + ]) + ->assertJson(fn(AssertableJson $json) => $json->has('rows', 3)->etc()); + + $this->actingAsForApi(User::factory()->viewUsers()->create()) + ->getJson(route('api.users.index', [ + 'filter' => '{"first_name":"Not Awesome"}', + ])) + ->assertOk() + ->assertJsonStructure([ + 'total', + 'rows', + ]) + ->assertJson(fn(AssertableJson $json) => $json->has('rows', 0)->etc()); } }