From 73e185bf9de0b9c1aa8fd08063b8e019c95443f0 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 15 Sep 2025 15:12:05 -0700 Subject: [PATCH 1/4] Scaffold route and tests --- app/Http/Controllers/Api/AssetsController.php | 4 ++ routes/api.php | 7 +++ .../Assets/Api/AssignedComponentsTest.php | 57 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 tests/Feature/Assets/Api/AssignedComponentsTest.php diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 755a50ccac..32f1a8b359 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -1322,6 +1322,10 @@ class AssetsController extends Controller return (new AssetsTransformer)->transformCheckedoutAccessories($accessory_checkouts, $total); } + public function assignedComponents(Request $request, Asset $asset): JsonResponse + { + // + } /** * Generate asset labels by tag diff --git a/routes/api.php b/routes/api.php index 988cedb645..a6697b6b19 100644 --- a/routes/api.php +++ b/routes/api.php @@ -571,6 +571,13 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu 'assignedAccessories' ] )->name('api.assets.assigned_accessories'); + + Route::get('{asset}/assigned/components', + [ + Api\AssetsController::class, + 'assignedComponents' + ] + )->name('api.assets.assigned_components'); /** End assigned routes */ }); diff --git a/tests/Feature/Assets/Api/AssignedComponentsTest.php b/tests/Feature/Assets/Api/AssignedComponentsTest.php new file mode 100644 index 0000000000..13156d8204 --- /dev/null +++ b/tests/Feature/Assets/Api/AssignedComponentsTest.php @@ -0,0 +1,57 @@ +actingAsForApi(User::factory()->create()) + ->getJson(route('api.assets.assigned_components', Asset::factory()->create())) + ->assertForbidden(); + } + + public function test_adheres_to_company_scoping() + { + $this->settings->enableMultipleFullCompanySupport(); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $asset = Asset::factory()->for($companyA)->create(); + + $user = User::factory()->for($companyB)->viewAssets()->create(); + + $this->actingAsForApi($user) + ->getJson(route('api.assets.assigned_components', $asset)) + ->assertOk() + ->assertStatusMessageIs('error') + ->assertMessagesAre('Asset not found'); + } + + public function test_can_get_components_assigned_to_specific_asset() + { + $unassociatedComponent = Component::factory()->create(); + + $asset = Asset::factory()->hasComponents(2)->create(); + + $componentsAssignedToAsset = $asset->components; + + $this->actingAsForApi(User::factory()->viewAssets()->create()) + ->getJson(route('api.assets.assigned_components', $asset)) + ->assertOk() + ->assertResponseContainsInRows($componentsAssignedToAsset) + ->assertResponseDoesNotContainInRows($unassociatedComponent) + ->assertJson(function (AssertableJson $json) { + $json->where('total', 2) + ->count('rows', 2) + ->etc(); + }); + } +} From 7393c4170b10c8b9de528255d6470603908fd9b5 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 15 Sep 2025 15:22:35 -0700 Subject: [PATCH 2/4] Apply first pass and scaffold additional test --- app/Http/Controllers/Api/AssetsController.php | 13 +++++++++++-- tests/Feature/Assets/Api/AssignedComponentsTest.php | 5 +++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 32f1a8b359..edc1bfde03 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -6,6 +6,7 @@ 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; @@ -1322,9 +1323,17 @@ class AssetsController extends Controller return (new AssetsTransformer)->transformCheckedoutAccessories($accessory_checkouts, $total); } - public function assignedComponents(Request $request, Asset $asset): JsonResponse + public function assignedComponents(Request $request, Asset $asset): JsonResponse|array { - // + $this->authorize('view', Asset::class); + $this->authorize('view', $asset); + + $asset->load('components'); + + $components = $asset->components; + $total = $asset->components->count(); + + return (new ComponentsTransformer)->transformComponents($components, $total); } /** diff --git a/tests/Feature/Assets/Api/AssignedComponentsTest.php b/tests/Feature/Assets/Api/AssignedComponentsTest.php index 13156d8204..9a5d7f28bb 100644 --- a/tests/Feature/Assets/Api/AssignedComponentsTest.php +++ b/tests/Feature/Assets/Api/AssignedComponentsTest.php @@ -54,4 +54,9 @@ class AssignedComponentsTest extends TestCase ->etc(); }); } + + public function test_adheres_to_offset_and_limit() + { + $this->markTestIncomplete(); + } } From 73e0628124bf8d7ff5b1aa0684d99942fb30fa3e Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 15 Sep 2025 15:26:30 -0700 Subject: [PATCH 3/4] Populate test --- .../Assets/Api/AssignedComponentsTest.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/Feature/Assets/Api/AssignedComponentsTest.php b/tests/Feature/Assets/Api/AssignedComponentsTest.php index 9a5d7f28bb..ad5ce43349 100644 --- a/tests/Feature/Assets/Api/AssignedComponentsTest.php +++ b/tests/Feature/Assets/Api/AssignedComponentsTest.php @@ -57,6 +57,23 @@ class AssignedComponentsTest extends TestCase public function test_adheres_to_offset_and_limit() { - $this->markTestIncomplete(); + $asset = Asset::factory()->hasComponents(2)->create(); + + $componentsAssignedToAsset = $asset->components; + + $this->actingAsForApi(User::factory()->viewAssets()->create()) + ->getJson(route('api.assets.assigned_components', [ + 'asset' => $asset, + 'offset' => 1, + 'limit' => 1, + ])) + ->assertOk() + ->assertResponseDoesNotContainInRows($componentsAssignedToAsset->first()) + ->assertResponseContainsInRows($componentsAssignedToAsset->last()) + ->assertJson(function (AssertableJson $json) { + $json->where('total', 2) + ->count('rows', 1) + ->etc(); + }); } } From 06f060161d66cfaa78afd244c711271a3e7a98eb Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 15 Sep 2025 15:43:54 -0700 Subject: [PATCH 4/4] Apply offset and limit --- app/Http/Controllers/Api/AssetsController.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index edc1bfde03..e3bd87bb26 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -1328,10 +1328,10 @@ class AssetsController extends Controller $this->authorize('view', Asset::class); $this->authorize('view', $asset); - $asset->load('components'); + $asset->loadCount('components'); + $total = $asset->components_count; - $components = $asset->components; - $total = $asset->components->count(); + $components = $asset->load(['components' => fn($query) => $query->applyOffsetAndLimit($total)])->components; return (new ComponentsTransformer)->transformComponents($components, $total); }