Merge pull request #17835 from marcusmoore/feature/10052-assigned-assets-via-api

Fixed #10052 - Added api endpoint for retrieving assets checked out to asset
This commit is contained in:
snipe
2025-09-15 08:38:35 +01:00
committed by GitHub
4 changed files with 124 additions and 8 deletions

View File

@@ -1290,9 +1290,19 @@ class AssetsController extends Controller
public function assignedAssets(Request $request, Asset $asset) : JsonResponse | array
{
$this->authorize('view', Asset::class);
$this->authorize('view', $asset);
return [];
// to do
$query = Asset::where([
'assigned_to' => $asset->id,
'assigned_type' => Asset::class,
]);
$total = $query->count();
$assets = $query->applyOffsetAndLimit($total)->get();
return (new AssetsTransformer)->transformAssets($assets, $total);
}
public function assignedAccessories(Request $request, Asset $asset) : JsonResponse | array

View File

@@ -3,8 +3,10 @@
namespace App\Models;
use App\Helpers\Helper;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Request;
class SnipeModel extends Model
{
@@ -156,6 +158,20 @@ class SnipeModel extends Model
$this->attributes['status_id'] = $value;
}
/**
* Applies offset (from request) and limit to query.
*
* @param Builder $query
* @param int $total
* @return void
*/
public function scopeApplyOffsetAndLimit(Builder $query, int $total)
{
$offset = (Request::input('offset') > $total) ? $total : app('api_offset_value');
$limit = app('api_limit_value');
$query->skip($offset)->take($limit);
}
protected function displayName(): Attribute
{

View File

@@ -0,0 +1,84 @@
<?php
namespace Tests\Feature\Assets\Api;
use App\Models\Asset;
use App\Models\Company;
use App\Models\User;
use Illuminate\Testing\Fluent\AssertableJson;
use Tests\TestCase;
class AssignedAssetsTest extends TestCase
{
public function test_requires_permission()
{
$this->actingAsForApi(User::factory()->create())
->getJson(route('api.assets.assigned_assets', 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_assets', $asset))
->assertOk()
->assertStatusMessageIs('error')
->assertMessagesAre('Asset not found');
}
public function test_can_get_assets_assigned_to_specific_asset()
{
$unassociatedAsset = Asset::factory()->create();
$asset = Asset::factory()->hasAssignedAssets(2)->create();
$assetsAssignedToAsset = Asset::where([
'assigned_to' => $asset->id,
'assigned_type' => Asset::class,
])->get();
$this->actingAsForApi(User::factory()->viewAssets()->create())
->getJson(route('api.assets.assigned_assets', $asset))
->assertOk()
->assertResponseContainsInRows($assetsAssignedToAsset, 'serial')
->assertResponseDoesNotContainInRows($unassociatedAsset, 'serial')
->assertJson(function (AssertableJson $json) {
$json->where('total', 2)
->count('rows', 2)
->etc();
});
}
public function test_adheres_to_offset_and_limit()
{
$asset = Asset::factory()->hasAssignedAssets(2)->create();
$assetsAssignedToAsset = Asset::where([
'assigned_to' => $asset->id,
'assigned_type' => Asset::class,
])->get();
$this->actingAsForApi(User::factory()->viewAssets()->create())
->getJson(route('api.assets.assigned_assets', [
'asset' => $asset,
'offset' => 1,
'limit' => 1,
]))
->assertOk()
->assertResponseDoesNotContainInRows($assetsAssignedToAsset->first(), 'serial')
->assertResponseContainsInRows($assetsAssignedToAsset->last(), 'serial')
->assertJson(function (AssertableJson $json) {
$json->where('total', 2)
->count('rows', 1)
->etc();
});
}
}

View File

@@ -21,13 +21,19 @@ trait CustomTestMacros
TestResponse::macro(
'assertResponseContainsInRows',
function (Model $model, string $property = 'name') use ($guardAgainstNullProperty) {
$guardAgainstNullProperty($model, $property);
function (iterable|Model $models, string $property = 'name') use ($guardAgainstNullProperty) {
if ($models instanceof Model) {
$models = [$models];
}
Assert::assertTrue(
collect($this['rows'])->pluck($property)->contains(e($model->{$property})),
"Response did not contain the expected value: {$model->{$property}}"
);
foreach ($models as $model) {
$guardAgainstNullProperty($model, $property);
Assert::assertTrue(
collect($this['rows'])->pluck($property)->contains(e($model->{$property})),
"Response did not contain the expected value: {$model->{$property}}"
);
}
return $this;
}