mirror of
https://github.com/snipe/snipe-it.git
synced 2024-12-25 05:34:06 -08:00
Merge pull request #13211 from marcusmoore/company-scoping
Improve testing around company scoping
This commit is contained in:
commit
e1fdfd01f6
|
@ -115,7 +115,7 @@ class AssetsController extends Controller
|
|||
$allowed_columns[] = $field->db_column_name();
|
||||
}
|
||||
|
||||
$assets = Company::scopeCompanyables(Asset::select('assets.*'), 'company_id', 'assets')
|
||||
$assets = Asset::select('assets.*')
|
||||
->with('location', 'assetstatus', 'company', 'defaultLoc','assignedTo',
|
||||
'model.category', 'model.manufacturer', 'model.fieldset','supplier'); //it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users.
|
||||
|
||||
|
@ -480,7 +480,7 @@ class AssetsController extends Controller
|
|||
public function selectlist(Request $request)
|
||||
{
|
||||
|
||||
$assets = Company::scopeCompanyables(Asset::select([
|
||||
$assets = Asset::select([
|
||||
'assets.id',
|
||||
'assets.name',
|
||||
'assets.asset_tag',
|
||||
|
@ -488,7 +488,7 @@ class AssetsController extends Controller
|
|||
'assets.assigned_to',
|
||||
'assets.assigned_type',
|
||||
'assets.status_id',
|
||||
])->with('model', 'assetstatus', 'assignedTo')->NotArchived(), 'company_id', 'assets');
|
||||
])->with('model', 'assetstatus', 'assignedTo')->NotArchived();
|
||||
|
||||
if ($request->filled('assetStatusType') && $request->input('assetStatusType') === 'RTD') {
|
||||
$assets = $assets->RTD();
|
||||
|
@ -1033,9 +1033,10 @@ class AssetsController extends Controller
|
|||
{
|
||||
$this->authorize('viewRequestable', Asset::class);
|
||||
|
||||
$assets = Company::scopeCompanyables(Asset::select('assets.*'), 'company_id', 'assets')
|
||||
$assets = Asset::select('assets.*')
|
||||
->with('location', 'assetstatus', 'assetlog', 'company', 'defaultLoc','assignedTo',
|
||||
'model.category', 'model.manufacturer', 'model.fieldset', 'supplier')->requestableAssets();
|
||||
'model.category', 'model.manufacturer', 'model.fieldset', 'supplier')
|
||||
->requestableAssets();
|
||||
|
||||
$offset = request('offset', 0);
|
||||
$limit = $request->input('limit', 50);
|
||||
|
|
|
@ -44,9 +44,8 @@ class ComponentsController extends Controller
|
|||
'notes',
|
||||
];
|
||||
|
||||
|
||||
$components = Company::scopeCompanyables(Component::select('components.*')
|
||||
->with('company', 'location', 'category', 'assets', 'supplier'));
|
||||
$components = Component::select('components.*')
|
||||
->with('company', 'location', 'category', 'assets', 'supplier');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$components = $components->TextSearch($request->input('search'));
|
||||
|
|
|
@ -45,11 +45,8 @@ class ConsumablesController extends Controller
|
|||
'notes',
|
||||
];
|
||||
|
||||
|
||||
$consumables = Company::scopeCompanyables(
|
||||
Consumable::select('consumables.*')
|
||||
->with('company', 'location', 'category', 'users', 'manufacturer')
|
||||
);
|
||||
$consumables = Consumable::select('consumables.*')
|
||||
->with('company', 'location', 'category', 'users', 'manufacturer');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$consumables = $consumables->TextSearch(e($request->input('search')));
|
||||
|
|
|
@ -26,8 +26,8 @@ class LicensesController extends Controller
|
|||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view', License::class);
|
||||
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'supplier','category')->withCount('freeSeats as free_seats_count'));
|
||||
|
||||
$licenses = License::with('company', 'manufacturer', 'supplier','category')->withCount('freeSeats as free_seats_count');
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$licenses->where('company_id', '=', $request->input('company_id'));
|
||||
|
|
|
@ -328,4 +328,14 @@ class AssetFactory extends Factory
|
|||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function requestable()
|
||||
{
|
||||
return $this->state(['requestable' => true]);
|
||||
}
|
||||
|
||||
public function nonrequestable()
|
||||
{
|
||||
return $this->state(['requestable' => false]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -271,6 +271,15 @@ class UserFactory extends Factory
|
|||
});
|
||||
}
|
||||
|
||||
public function viewDepartments()
|
||||
{
|
||||
return $this->state(function () {
|
||||
return [
|
||||
'permissions' => '{"departments.view":"1"}',
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function viewLicenses()
|
||||
{
|
||||
return $this->state(function () {
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
namespace Tests\Feature\Api\Assets;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Illuminate\Testing\Fluent\AssertableJson;
|
||||
use Laravel\Passport\Passport;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
|
@ -17,14 +17,14 @@ class AssetIndexTest extends TestCase
|
|||
{
|
||||
Asset::factory()->count(3)->create();
|
||||
|
||||
Passport::actingAs(User::factory()->superuser()->create());
|
||||
$this->getJson(
|
||||
route('api.assets.index', [
|
||||
'sort' => 'name',
|
||||
'order' => 'asc',
|
||||
'offset' => '0',
|
||||
'limit' => '20',
|
||||
]))
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->getJson(
|
||||
route('api.assets.index', [
|
||||
'sort' => 'name',
|
||||
'order' => 'asc',
|
||||
'offset' => '0',
|
||||
'limit' => '20',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertJsonStructure([
|
||||
'total',
|
||||
|
@ -32,4 +32,50 @@ class AssetIndexTest extends TestCase
|
|||
])
|
||||
->assertJson(fn(AssertableJson $json) => $json->has('rows', 3)->etc());
|
||||
}
|
||||
|
||||
public function testAssetIndexAdheresToCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$assetA = Asset::factory()->for($companyA)->create();
|
||||
$assetB = Asset::factory()->for($companyB)->create();
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->viewAssets()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->viewAssets()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseDoesNotContainInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.assets.index'))
|
||||
->assertResponseDoesNotContainInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
}
|
||||
}
|
||||
|
|
76
tests/Feature/Api/Assets/AssetsForSelectListTest.php
Normal file
76
tests/Feature/Api/Assets/AssetsForSelectListTest.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Assets;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetsForSelectListTest extends TestCase
|
||||
{
|
||||
use InteractsWithSettings;
|
||||
|
||||
public function testAssetsCanBeSearchedForByAssetTag()
|
||||
{
|
||||
Asset::factory()->create(['asset_tag' => '0001']);
|
||||
Asset::factory()->create(['asset_tag' => '0002']);
|
||||
|
||||
$response = $this->actingAsForApi(User::factory()->create())
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertOk();
|
||||
|
||||
$results = collect($response->json('results'));
|
||||
|
||||
$this->assertEquals(2, $results->count());
|
||||
$this->assertTrue($results->pluck('text')->contains(fn($text) => str_contains($text, '0001')));
|
||||
$this->assertTrue($results->pluck('text')->contains(fn($text) => str_contains($text, '0002')));
|
||||
}
|
||||
|
||||
public function testAssetsAreScopedToCompanyWhenMultipleCompanySupportEnabled()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$assetA = Asset::factory()->for($companyA)->create(['asset_tag' => '0001']);
|
||||
$assetB = Asset::factory()->for($companyB)->create(['asset_tag' => '0002']);
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->viewAssets()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->viewAssets()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseContainsInResults($assetA)
|
||||
->assertResponseDoesNotContainInResults($assetB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('assets.selectlist', ['search' => '000']))
|
||||
->assertResponseDoesNotContainInResults($assetA)
|
||||
->assertResponseContainsInResults($assetB);
|
||||
}
|
||||
}
|
79
tests/Feature/Api/Assets/RequestableAssetsTest.php
Normal file
79
tests/Feature/Api/Assets/RequestableAssetsTest.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Assets;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
class RequestableAssetsTest extends TestCase
|
||||
{
|
||||
use InteractsWithSettings;
|
||||
|
||||
public function testViewingRequestableAssetsRequiresCorrectPermission()
|
||||
{
|
||||
$this->actingAsForApi(User::factory()->create())
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function testReturnsRequestableAssets()
|
||||
{
|
||||
$requestableAsset = Asset::factory()->requestable()->create(['asset_tag' => 'requestable']);
|
||||
$nonRequestableAsset = Asset::factory()->nonrequestable()->create(['asset_tag' => 'non-requestable']);
|
||||
|
||||
$this->actingAsForApi(User::factory()->viewRequestableAssets()->create())
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertOk()
|
||||
->assertResponseContainsInRows($requestableAsset, 'asset_tag')
|
||||
->assertResponseDoesNotContainInRows($nonRequestableAsset, 'asset_tag');
|
||||
}
|
||||
|
||||
public function testRequestableAssetsAreScopedToCompanyWhenMultipleCompanySupportEnabled()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$assetA = Asset::factory()->requestable()->for($companyA)->create(['asset_tag' => '0001']);
|
||||
$assetB = Asset::factory()->requestable()->for($companyB)->create(['asset_tag' => '0002']);
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->viewRequestableAssets()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->viewRequestableAssets()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseContainsInRows($assetA, 'asset_tag')
|
||||
->assertResponseDoesNotContainInRows($assetB, 'asset_tag');
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.assets.requestable'))
|
||||
->assertResponseDoesNotContainInRows($assetA, 'asset_tag')
|
||||
->assertResponseContainsInRows($assetB, 'asset_tag');
|
||||
}
|
||||
}
|
60
tests/Feature/Api/Components/ComponentIndexTest.php
Normal file
60
tests/Feature/Api/Components/ComponentIndexTest.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Components;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\Component;
|
||||
use App\Models\User;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ComponentIndexTest extends TestCase
|
||||
{
|
||||
use InteractsWithSettings;
|
||||
|
||||
public function testComponentIndexAdheresToCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$componentA = Component::factory()->for($companyA)->create();
|
||||
$componentB = Component::factory()->for($companyB)->create();
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->viewComponents()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->viewComponents()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseContainsInRows($componentA)
|
||||
->assertResponseDoesNotContainInRows($componentB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.components.index'))
|
||||
->assertResponseDoesNotContainInRows($componentA)
|
||||
->assertResponseContainsInRows($componentB);
|
||||
}
|
||||
}
|
60
tests/Feature/Api/Consumables/ConsumablesIndexTest.php
Normal file
60
tests/Feature/Api/Consumables/ConsumablesIndexTest.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Consumables;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\User;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ConsumablesIndexTest extends TestCase
|
||||
{
|
||||
use InteractsWithSettings;
|
||||
|
||||
public function testConsumableIndexAdheresToCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$consumableA = Consumable::factory()->for($companyA)->create();
|
||||
$consumableB = Consumable::factory()->for($companyB)->create();
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->viewConsumables()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->viewConsumables()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseContainsInRows($consumableA)
|
||||
->assertResponseDoesNotContainInRows($consumableB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.consumables.index'))
|
||||
->assertResponseDoesNotContainInRows($consumableA)
|
||||
->assertResponseContainsInRows($consumableB);
|
||||
}
|
||||
}
|
60
tests/Feature/Api/Licenses/LicensesIndexTest.php
Normal file
60
tests/Feature/Api/Licenses/LicensesIndexTest.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Licenses;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\License;
|
||||
use App\Models\User;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
class LicensesIndexTest extends TestCase
|
||||
{
|
||||
use InteractsWithSettings;
|
||||
|
||||
public function testLicensesIndexAdheresToCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$licenseA = License::factory()->for($companyA)->create();
|
||||
$licenseB = License::factory()->for($companyB)->create();
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->viewLicenses()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->viewLicenses()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAsForApi($superUser)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyA)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseContainsInRows($licenseA)
|
||||
->assertResponseDoesNotContainInRows($licenseB);
|
||||
|
||||
$this->actingAsForApi($userInCompanyB)
|
||||
->getJson(route('api.licenses.index'))
|
||||
->assertResponseDoesNotContainInRows($licenseA)
|
||||
->assertResponseContainsInRows($licenseB);
|
||||
}
|
||||
}
|
19
tests/Feature/DashboardTest.php
Normal file
19
tests/Feature/DashboardTest.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\User;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
class DashboardTest extends TestCase
|
||||
{
|
||||
use InteractsWithSettings;
|
||||
|
||||
public function testUsersWithoutAdminAccessAreRedirected()
|
||||
{
|
||||
$this->actingAs(User::factory()->create())
|
||||
->get(route('home'))
|
||||
->assertRedirect(route('view-assets'));
|
||||
}
|
||||
}
|
66
tests/Support/CustomTestMacros.php
Normal file
66
tests/Support/CustomTestMacros.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Support;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Testing\TestResponse;
|
||||
use PHPUnit\Framework\Assert;
|
||||
use RuntimeException;
|
||||
|
||||
trait CustomTestMacros
|
||||
{
|
||||
protected function registerCustomMacros()
|
||||
{
|
||||
$guardAgainstNullProperty = function (Model $model, string $property) {
|
||||
if (is_null($model->{$property})) {
|
||||
throw new RuntimeException(
|
||||
"The property ({$property}) either does not exist or is null on the model which isn't helpful for comparison."
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
TestResponse::macro(
|
||||
'assertResponseContainsInRows',
|
||||
function (Model $model, string $property = 'name') use ($guardAgainstNullProperty) {
|
||||
$guardAgainstNullProperty($model, $property);
|
||||
|
||||
Assert::assertTrue(collect($this['rows'])->pluck($property)->contains($model->{$property}));
|
||||
|
||||
return $this;
|
||||
}
|
||||
);
|
||||
|
||||
TestResponse::macro(
|
||||
'assertResponseDoesNotContainInRows',
|
||||
function (Model $model, string $property = 'name') use ($guardAgainstNullProperty) {
|
||||
$guardAgainstNullProperty($model, $property);
|
||||
|
||||
Assert::assertFalse(collect($this['rows'])->pluck($property)->contains($model->{$property}));
|
||||
|
||||
return $this;
|
||||
}
|
||||
);
|
||||
|
||||
TestResponse::macro(
|
||||
'assertResponseContainsInResults',
|
||||
function (Model $model, string $property = 'id') use ($guardAgainstNullProperty) {
|
||||
$guardAgainstNullProperty($model, $property);
|
||||
|
||||
Assert::assertTrue(collect($this->json('results'))->pluck('id')->contains($model->{$property}));
|
||||
|
||||
return $this;
|
||||
}
|
||||
);
|
||||
|
||||
TestResponse::macro(
|
||||
'assertResponseDoesNotContainInResults',
|
||||
function (Model $model, string $property = 'id') use ($guardAgainstNullProperty) {
|
||||
$guardAgainstNullProperty($model, $property);
|
||||
|
||||
Assert::assertFalse(collect($this->json('results'))->pluck('id')->contains($model->{$property}));
|
||||
|
||||
return $this;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
16
tests/Support/InteractsWithAuthentication.php
Normal file
16
tests/Support/InteractsWithAuthentication.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Support;
|
||||
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Laravel\Passport\Passport;
|
||||
|
||||
trait InteractsWithAuthentication
|
||||
{
|
||||
protected function actingAsForApi(Authenticatable $user)
|
||||
{
|
||||
Passport::actingAs($user);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -33,6 +33,11 @@ class Settings
|
|||
return $this->update(['full_multiple_companies_support' => 1]);
|
||||
}
|
||||
|
||||
public function disableMultipleFullCompanySupport(): Settings
|
||||
{
|
||||
return $this->update(['full_multiple_companies_support' => 0]);
|
||||
}
|
||||
|
||||
public function enableWebhook(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
|
|
|
@ -5,11 +5,15 @@ namespace Tests;
|
|||
use App\Http\Middleware\SecurityHeaders;
|
||||
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
|
||||
use Tests\Support\CustomTestMacros;
|
||||
use Tests\Support\InteractsWithAuthentication;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
use CreatesApplication;
|
||||
use CustomTestMacros;
|
||||
use InteractsWithAuthentication;
|
||||
use LazilyRefreshDatabase;
|
||||
|
||||
private array $globallyDisabledMiddleware = [
|
||||
|
@ -25,5 +29,7 @@ abstract class TestCase extends BaseTestCase
|
|||
if (collect(class_uses_recursive($this))->contains(InteractsWithSettings::class)) {
|
||||
$this->initializeSettings();
|
||||
}
|
||||
|
||||
$this->registerCustomMacros();
|
||||
}
|
||||
}
|
||||
|
|
169
tests/Unit/CompanyScopingTest.php
Normal file
169
tests/Unit/CompanyScopingTest.php
Normal file
|
@ -0,0 +1,169 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\Company;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\License;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Tests\Support\InteractsWithSettings;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CompanyScopingTest extends TestCase
|
||||
{
|
||||
use InteractsWithSettings;
|
||||
|
||||
public function models(): array
|
||||
{
|
||||
return [
|
||||
'Accessories' => [Accessory::class],
|
||||
'Assets' => [Asset::class],
|
||||
'Components' => [Component::class],
|
||||
'Consumables' => [Consumable::class],
|
||||
'Licenses' => [License::class],
|
||||
];
|
||||
}
|
||||
|
||||
/** @dataProvider models */
|
||||
public function testCompanyScoping($model)
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$modelA = $model::factory()->for($companyA)->create();
|
||||
$modelB = $model::factory()->for($companyB)->create();
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($superUser);
|
||||
$this->assertCanSee($modelA);
|
||||
$this->assertCanSee($modelB);
|
||||
|
||||
$this->actingAs($userInCompanyA);
|
||||
$this->assertCanSee($modelA);
|
||||
$this->assertCanSee($modelB);
|
||||
|
||||
$this->actingAs($userInCompanyB);
|
||||
$this->assertCanSee($modelA);
|
||||
$this->assertCanSee($modelB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($superUser);
|
||||
$this->assertCanSee($modelA);
|
||||
$this->assertCanSee($modelB);
|
||||
|
||||
$this->actingAs($userInCompanyA);
|
||||
$this->assertCanSee($modelA);
|
||||
$this->assertCannotSee($modelB);
|
||||
|
||||
$this->actingAs($userInCompanyB);
|
||||
$this->assertCannotSee($modelA);
|
||||
$this->assertCanSee($modelB);
|
||||
}
|
||||
|
||||
public function testAssetMaintenanceCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$assetMaintenanceForCompanyA = AssetMaintenance::factory()->for(Asset::factory()->for($companyA))->create();
|
||||
$assetMaintenanceForCompanyB = AssetMaintenance::factory()->for(Asset::factory()->for($companyB))->create();
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($superUser);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyA);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyB);
|
||||
|
||||
$this->actingAs($userInCompanyA);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyA);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyB);
|
||||
|
||||
$this->actingAs($userInCompanyB);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyA);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($superUser);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyA);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyB);
|
||||
|
||||
$this->actingAs($userInCompanyA);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyA);
|
||||
$this->assertCannotSee($assetMaintenanceForCompanyB);
|
||||
|
||||
$this->actingAs($userInCompanyB);
|
||||
$this->assertCannotSee($assetMaintenanceForCompanyA);
|
||||
$this->assertCanSee($assetMaintenanceForCompanyB);
|
||||
}
|
||||
|
||||
public function testLicenseSeatCompanyScoping()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
|
||||
$licenseSeatA = LicenseSeat::factory()->for(Asset::factory()->for($companyA))->create();
|
||||
$licenseSeatB = LicenseSeat::factory()->for(Asset::factory()->for($companyB))->create();
|
||||
|
||||
$superUser = $companyA->users()->save(User::factory()->superuser()->make());
|
||||
$userInCompanyA = $companyA->users()->save(User::factory()->make());
|
||||
$userInCompanyB = $companyB->users()->save(User::factory()->make());
|
||||
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($superUser);
|
||||
$this->assertCanSee($licenseSeatA);
|
||||
$this->assertCanSee($licenseSeatB);
|
||||
|
||||
$this->actingAs($userInCompanyA);
|
||||
$this->assertCanSee($licenseSeatA);
|
||||
$this->assertCanSee($licenseSeatB);
|
||||
|
||||
$this->actingAs($userInCompanyB);
|
||||
$this->assertCanSee($licenseSeatA);
|
||||
$this->assertCanSee($licenseSeatB);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($superUser);
|
||||
$this->assertCanSee($licenseSeatA);
|
||||
$this->assertCanSee($licenseSeatB);
|
||||
|
||||
$this->actingAs($userInCompanyA);
|
||||
$this->assertCanSee($licenseSeatA);
|
||||
$this->assertCannotSee($licenseSeatB);
|
||||
|
||||
$this->actingAs($userInCompanyB);
|
||||
$this->assertCannotSee($licenseSeatA);
|
||||
$this->assertCanSee($licenseSeatB);
|
||||
}
|
||||
|
||||
private function assertCanSee(Model $model)
|
||||
{
|
||||
$this->assertTrue(
|
||||
get_class($model)::all()->contains($model),
|
||||
'User was not able to see expected model'
|
||||
);
|
||||
}
|
||||
|
||||
private function assertCannotSee(Model $model)
|
||||
{
|
||||
$this->assertFalse(
|
||||
get_class($model)::all()->contains($model),
|
||||
'User was able to see model from a different company'
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue