From deca80ba71e6846c9fbb04afb4bb95acad417c68 Mon Sep 17 00:00:00 2001 From: akemidx Date: Wed, 17 May 2023 13:17:48 -0400 Subject: [PATCH 01/56] checkin/out info on side bar --- resources/lang/en/admin/hardware/general.php | 2 +- resources/views/hardware/view.blade.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/resources/lang/en/admin/hardware/general.php b/resources/lang/en/admin/hardware/general.php index b0a48f2ce4..7201d37053 100644 --- a/resources/lang/en/admin/hardware/general.php +++ b/resources/lang/en/admin/hardware/general.php @@ -19,7 +19,7 @@ return [ 'requestable' => 'Requestable', 'requested' => 'Requested', 'not_requestable' => 'Not Requestable', - 'requestable_status_warning' => 'Do not change requestable status', + 'requestable_status_warning' => 'Do not change requestable status', 'restore' => 'Restore Asset', 'pending' => 'Pending', 'undeployable' => 'Undeployable', diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index 50b80de0f2..207f18e680 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -934,6 +934,14 @@ {{ $asset->location->state }} {{ $asset->location->zip }} @endif +
  • + {{ trans('admin/hardware/form.checkout_date') }}: {{ Helper::getFormattedDateObject($asset->last_checkout, 'date', false) }} +
  • + @if (isset($asset->expected_checkin)) +
  • + {{ trans('admin/hardware/form.expected_checkin') }}: {{ Helper::getFormattedDateObject($asset->expected_checkin, 'date', false) }} +
  • + @endif @endif From 6585aa0cf071b5ce40900f7b87c816608cca3da2 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 6 Jun 2023 16:31:14 -0700 Subject: [PATCH 02/56] Add unit tests for company scoping --- tests/Support/Settings.php | 5 + tests/Unit/CompanyScopingTest.php | 169 ++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 tests/Unit/CompanyScopingTest.php diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php index 70022e53c3..fa8886b751 100644 --- a/tests/Support/Settings.php +++ b/tests/Support/Settings.php @@ -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([ diff --git a/tests/Unit/CompanyScopingTest.php b/tests/Unit/CompanyScopingTest.php new file mode 100644 index 0000000000..669dd5ed41 --- /dev/null +++ b/tests/Unit/CompanyScopingTest.php @@ -0,0 +1,169 @@ + [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' + ); + } +} From 42a4941ad2ea75e868f76bb8b7a2e08bca5c7559 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 5 Jun 2023 12:17:44 -0700 Subject: [PATCH 03/56] Ensure consumable name is valid in factory --- database/factories/ConsumableFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/factories/ConsumableFactory.php b/database/factories/ConsumableFactory.php index 5444999711..ea303eccae 100644 --- a/database/factories/ConsumableFactory.php +++ b/database/factories/ConsumableFactory.php @@ -27,7 +27,7 @@ class ConsumableFactory extends Factory public function definition() { return [ - 'name' => $this->faker->word(), + 'name' => $this->faker->words(), 'category_id' => Category::factory(), 'user_id' => User::factory()->superuser(), 'item_no' => $this->faker->numberBetween(1000000, 50000000), From 4fb86ad2fbb66d0cf6da66e5a61cf5b30d9fedbe Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 5 Jun 2023 12:57:09 -0700 Subject: [PATCH 04/56] Get name as a string and not an array --- database/factories/ConsumableFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/factories/ConsumableFactory.php b/database/factories/ConsumableFactory.php index ea303eccae..18a116418b 100644 --- a/database/factories/ConsumableFactory.php +++ b/database/factories/ConsumableFactory.php @@ -27,7 +27,7 @@ class ConsumableFactory extends Factory public function definition() { return [ - 'name' => $this->faker->words(), + 'name' => $this->faker->words(3, true), 'category_id' => Category::factory(), 'user_id' => User::factory()->superuser(), 'item_no' => $this->faker->numberBetween(1000000, 50000000), From 48850f35971fb142207eb9c8f77cb9335fe5130f Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 6 Jun 2023 18:02:18 -0700 Subject: [PATCH 05/56] Remove scopeCompanyables call from ComponentsController --- .../Controllers/Api/ComponentsController.php | 4 +- .../Api/Components/ComponentIndexTest.php | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 tests/Feature/Api/Components/ComponentIndexTest.php diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index 24eb1044b8..59d12c920e 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -44,9 +44,7 @@ class ComponentsController extends Controller 'notes', ]; - - $components = Company::scopeCompanyables(Component::select('components.*') - ->with('company', 'location', 'category', 'assets', 'supplier')); + $components = Component::with('company', 'location', 'category', 'assets', 'supplier'); if ($request->filled('search')) { $components = $components->TextSearch($request->input('search')); diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php new file mode 100644 index 0000000000..e459e9f8f6 --- /dev/null +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -0,0 +1,77 @@ +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(); + + Passport::actingAs($superUser); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseContains($response, $componentB); + + Passport::actingAs($userInCompanyA); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseContains($response, $componentB); + + Passport::actingAs($userInCompanyB); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseContains($response, $componentB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseContains($response, $componentB); + + Passport::actingAs($userInCompanyA); + $response = $this->sendRequest(); + $this->assertResponseContains($response, $componentA); + $this->assertResponseDoesNotContain($response, $componentB); + + Passport::actingAs($userInCompanyB); + $response = $this->sendRequest(); + $this->assertResponseDoesNotContain($response, $componentA); + $this->assertResponseContains($response, $componentB); + } + + private function sendRequest(): TestResponse + { + return $this->getJson(route('api.components.index')); + } + + private function assertResponseContains(TestResponse $response, Component $component) + { + $this->assertTrue(collect($response['rows'])->pluck('name')->contains($component->name)); + } + + private function assertResponseDoesNotContain(TestResponse $response, Component $component) + { + $this->assertFalse(collect($response['rows'])->pluck('name')->contains($component->name)); + } +} From a18f5e7fc0c2ce339b2c6247e239820a57c67622 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 14:22:22 -0700 Subject: [PATCH 06/56] Remove scopeCompanyables call from ConsumablesController --- .../Controllers/Api/ConsumablesController.php | 6 +- .../Api/Consumables/ConsumablesIndexTest.php | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 tests/Feature/Api/Consumables/ConsumablesIndexTest.php diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index bac9440dca..385f306c25 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -45,11 +45,7 @@ class ConsumablesController extends Controller 'notes', ]; - - $consumables = Company::scopeCompanyables( - Consumable::select('consumables.*') - ->with('company', 'location', 'category', 'users', 'manufacturer') - ); + $consumables = Consumable::with('company', 'location', 'category', 'users', 'manufacturer'); if ($request->filled('search')) { $consumables = $consumables->TextSearch(e($request->input('search'))); diff --git a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php new file mode 100644 index 0000000000..1d1a627c65 --- /dev/null +++ b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php @@ -0,0 +1,72 @@ +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(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseContains($response, $consumableA); + $this->assertResponseDoesNotContain($response, $consumableB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.consumables.index')); + $this->assertResponseDoesNotContain($response, $consumableA); + $this->assertResponseContains($response, $consumableB); + } + + private function assertResponseContains(TestResponse $response, Consumable $consumable) + { + $this->assertTrue(collect($response['rows'])->pluck('name')->contains($consumable->name)); + } + + private function assertResponseDoesNotContain(TestResponse $response, Consumable $consumable) + { + $this->assertFalse(collect($response['rows'])->pluck('name')->contains($consumable->name)); + } +} From 8e6e525b47bdd5cbb0f9d81bdafc614bd532a663 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:09:45 -0700 Subject: [PATCH 07/56] Remove scopeCompanyables call from LicensesController --- .../Controllers/Api/LicensesController.php | 2 +- .../Api/Licenses/LicensesIndexTest.php | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/Api/Licenses/LicensesIndexTest.php diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index df74b60895..e021fc3d3e 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -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')); diff --git a/tests/Feature/Api/Licenses/LicensesIndexTest.php b/tests/Feature/Api/Licenses/LicensesIndexTest.php new file mode 100644 index 0000000000..4deb6bbcbe --- /dev/null +++ b/tests/Feature/Api/Licenses/LicensesIndexTest.php @@ -0,0 +1,72 @@ +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(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseContains($response, $licenseA); + $this->assertResponseDoesNotContain($response, $licenseB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.licenses.index')); + $this->assertResponseDoesNotContain($response, $licenseA); + $this->assertResponseContains($response, $licenseB); + } + + private function assertResponseContains(TestResponse $response, License $license) + { + $this->assertTrue(collect($response['rows'])->pluck('name')->contains($license->name)); + } + + private function assertResponseDoesNotContain(TestResponse $response, License $license) + { + $this->assertFalse(collect($response['rows'])->pluck('name')->contains($license->name)); + } +} From 27d4d107bb3a142793b871859f4866c2f23da531 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:10:29 -0700 Subject: [PATCH 08/56] Scaffold test before removing scopeCompanyables call from DepartmentsController --- database/factories/UserFactory.php | 9 +++ .../Api/Departments/DepartmentsIndexTest.php | 74 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tests/Feature/Api/Departments/DepartmentsIndexTest.php diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 8aa38d2325..586cb7186b 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -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 () { diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php new file mode 100644 index 0000000000..a79a4f89ef --- /dev/null +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -0,0 +1,74 @@ +markTestIncomplete(); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $departmentA = Department::factory()->for($companyA)->create(); + $departmentB = Department::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewDepartments()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewDepartments()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseContains($response, $departmentA); + $this->assertResponseDoesNotContain($response, $departmentB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.departments.index')); + $this->assertResponseDoesNotContain($response, $departmentA); + $this->assertResponseContains($response, $departmentB); + } + + private function assertResponseContains(TestResponse $response, Department $department) + { + $this->assertTrue(collect($response['rows'])->pluck('name')->contains($department->name)); + } + + private function assertResponseDoesNotContain(TestResponse $response, Department $department) + { + $this->assertFalse(collect($response['rows'])->pluck('name')->contains($department->name)); + } +} From abaf59c9902a54515212f29f370e2d58b77e5d68 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:16:30 -0700 Subject: [PATCH 09/56] Extract and use helper methods --- .../Api/Components/ComponentIndexTest.php | 36 +++++++----------- .../Api/Consumables/ConsumablesIndexTest.php | 37 +++++++------------ .../Api/Departments/DepartmentsIndexTest.php | 37 +++++++------------ .../Api/Licenses/LicensesIndexTest.php | 37 +++++++------------ tests/Support/InteractsWithResponses.php | 19 ++++++++++ 5 files changed, 75 insertions(+), 91 deletions(-) create mode 100644 tests/Support/InteractsWithResponses.php diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php index e459e9f8f6..978d4be10b 100644 --- a/tests/Feature/Api/Components/ComponentIndexTest.php +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -7,11 +7,13 @@ use App\Models\Component; use App\Models\User; use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; +use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ComponentIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testComponentIndexAdheresToCompanyScoping() @@ -29,49 +31,39 @@ class ComponentIndexTest extends TestCase Passport::actingAs($superUser); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyA); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyB); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyA); $response = $this->sendRequest(); - $this->assertResponseContains($response, $componentA); - $this->assertResponseDoesNotContain($response, $componentB); + $this->assertResponseContainsInRows($response, $componentA); + $this->assertResponseDoesNotContainInRows($response, $componentB); Passport::actingAs($userInCompanyB); $response = $this->sendRequest(); - $this->assertResponseDoesNotContain($response, $componentA); - $this->assertResponseContains($response, $componentB); + $this->assertResponseDoesNotContainInRows($response, $componentA); + $this->assertResponseContainsInRows($response, $componentB); } private function sendRequest(): TestResponse { return $this->getJson(route('api.components.index')); } - - private function assertResponseContains(TestResponse $response, Component $component) - { - $this->assertTrue(collect($response['rows'])->pluck('name')->contains($component->name)); - } - - private function assertResponseDoesNotContain(TestResponse $response, Component $component) - { - $this->assertFalse(collect($response['rows'])->pluck('name')->contains($component->name)); - } } diff --git a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php index 1d1a627c65..11a4d79afa 100644 --- a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php +++ b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php @@ -5,13 +5,14 @@ namespace Tests\Feature\Api\Consumables; use App\Models\Company; use App\Models\Consumable; use App\Models\User; -use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; +use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ConsumablesIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testConsumableIndexAdheresToCompanyScoping() @@ -29,44 +30,34 @@ class ConsumablesIndexTest extends TestCase Passport::actingAs($superUser); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseContains($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseContains($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseContains($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseContains($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContains($response, $consumableA); - $this->assertResponseDoesNotContain($response, $consumableB); + $this->assertResponseContainsInRows($response, $consumableA); + $this->assertResponseDoesNotContainInRows($response, $consumableB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseDoesNotContain($response, $consumableA); - $this->assertResponseContains($response, $consumableB); - } - - private function assertResponseContains(TestResponse $response, Consumable $consumable) - { - $this->assertTrue(collect($response['rows'])->pluck('name')->contains($consumable->name)); - } - - private function assertResponseDoesNotContain(TestResponse $response, Consumable $consumable) - { - $this->assertFalse(collect($response['rows'])->pluck('name')->contains($consumable->name)); + $this->assertResponseDoesNotContainInRows($response, $consumableA); + $this->assertResponseContainsInRows($response, $consumableB); } } diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php index a79a4f89ef..d791c79e93 100644 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -5,13 +5,14 @@ namespace Tests\Feature\Api\Departments; use App\Models\Company; use App\Models\Department; use App\Models\User; -use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; +use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class DepartmentsIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testDepartmentsIndexAdheresToCompanyScoping() @@ -31,44 +32,34 @@ class DepartmentsIndexTest extends TestCase Passport::actingAs($superUser); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseContains($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseContains($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseContains($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseContains($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContains($response, $departmentA); - $this->assertResponseDoesNotContain($response, $departmentB); + $this->assertResponseContainsInRows($response, $departmentA); + $this->assertResponseDoesNotContainInRows($response, $departmentB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.departments.index')); - $this->assertResponseDoesNotContain($response, $departmentA); - $this->assertResponseContains($response, $departmentB); - } - - private function assertResponseContains(TestResponse $response, Department $department) - { - $this->assertTrue(collect($response['rows'])->pluck('name')->contains($department->name)); - } - - private function assertResponseDoesNotContain(TestResponse $response, Department $department) - { - $this->assertFalse(collect($response['rows'])->pluck('name')->contains($department->name)); + $this->assertResponseDoesNotContainInRows($response, $departmentA); + $this->assertResponseContainsInRows($response, $departmentB); } } diff --git a/tests/Feature/Api/Licenses/LicensesIndexTest.php b/tests/Feature/Api/Licenses/LicensesIndexTest.php index 4deb6bbcbe..404eb31238 100644 --- a/tests/Feature/Api/Licenses/LicensesIndexTest.php +++ b/tests/Feature/Api/Licenses/LicensesIndexTest.php @@ -5,13 +5,14 @@ namespace Tests\Feature\Api\Licenses; use App\Models\Company; use App\Models\License; use App\Models\User; -use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; +use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class LicensesIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testLicensesIndexAdheresToCompanyScoping() @@ -29,44 +30,34 @@ class LicensesIndexTest extends TestCase Passport::actingAs($superUser); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseContains($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseContains($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseContains($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseContains($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); Passport::actingAs($userInCompanyA); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContains($response, $licenseA); - $this->assertResponseDoesNotContain($response, $licenseB); + $this->assertResponseContainsInRows($response, $licenseA); + $this->assertResponseDoesNotContainInRows($response, $licenseB); Passport::actingAs($userInCompanyB); $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseDoesNotContain($response, $licenseA); - $this->assertResponseContains($response, $licenseB); - } - - private function assertResponseContains(TestResponse $response, License $license) - { - $this->assertTrue(collect($response['rows'])->pluck('name')->contains($license->name)); - } - - private function assertResponseDoesNotContain(TestResponse $response, License $license) - { - $this->assertFalse(collect($response['rows'])->pluck('name')->contains($license->name)); + $this->assertResponseDoesNotContainInRows($response, $licenseA); + $this->assertResponseContainsInRows($response, $licenseB); } } diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php new file mode 100644 index 0000000000..3206aaea9d --- /dev/null +++ b/tests/Support/InteractsWithResponses.php @@ -0,0 +1,19 @@ +assertTrue(collect($response['rows'])->pluck($field)->contains($model->{$field})); + } + + private function assertResponseDoesNotContainInRows(TestResponse $response, Model $model, string $field = 'name') + { + $this->assertFalse(collect($response['rows'])->pluck($field)->contains($model->{$field})); + } +} From 0f6051bbe574c923be5953d1074d7d776f4e825b Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:18:02 -0700 Subject: [PATCH 10/56] Inline method call --- .../Api/Components/ComponentIndexTest.php | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php index 978d4be10b..845ce29b99 100644 --- a/tests/Feature/Api/Components/ComponentIndexTest.php +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Components; use App\Models\Company; use App\Models\Component; use App\Models\User; -use Illuminate\Testing\TestResponse; use Laravel\Passport\Passport; use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; @@ -30,40 +29,35 @@ class ComponentIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyA); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyB); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); Passport::actingAs($userInCompanyA); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseContainsInRows($response, $componentA); $this->assertResponseDoesNotContainInRows($response, $componentB); Passport::actingAs($userInCompanyB); - $response = $this->sendRequest(); + $response = $this->getJson(route('api.components.index')); $this->assertResponseDoesNotContainInRows($response, $componentA); $this->assertResponseContainsInRows($response, $componentB); } - - private function sendRequest(): TestResponse - { - return $this->getJson(route('api.components.index')); - } } From 6f5252449e4e5dad664c77ff4e73da4cd518fc7e Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 16:25:18 -0700 Subject: [PATCH 11/56] Scaffold test before removing scopeCompanyables call from UsersController --- tests/Feature/Api/Users/UsersIndexTest.php | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/Feature/Api/Users/UsersIndexTest.php diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php new file mode 100644 index 0000000000..16893cd174 --- /dev/null +++ b/tests/Feature/Api/Users/UsersIndexTest.php @@ -0,0 +1,64 @@ +markTestIncomplete(); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $userA = User::factory()->for($companyA)->create(); + $userB = User::factory()->for($companyB)->create(); + + $superUser = $companyA->users()->save(User::factory()->superuser()->make()); + $userInCompanyA = $companyA->users()->save(User::factory()->viewUsers()->make()); + $userInCompanyB = $companyB->users()->save(User::factory()->viewUsers()->make()); + + $this->settings->disableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseContainsInRows($response, $userA, 'first_name'); + $this->assertResponseDoesNotContainInRows($response, $userB, 'first_name'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.users.index')); + $this->assertResponseDoesNotContainInRows($response, $userA, 'first_name'); + $this->assertResponseContainsInRows($response, $userB, 'first_name'); + } +} From 7672861b96ac5ba1487d99153cc6ce1a6b0c344d Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 7 Jun 2023 17:38:23 -0700 Subject: [PATCH 12/56] Scaffold test before removing scopeCompanyables call from DashboardController --- tests/Feature/DashboardTest.php | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/Feature/DashboardTest.php diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php new file mode 100644 index 0000000000..c5c41d268e --- /dev/null +++ b/tests/Feature/DashboardTest.php @@ -0,0 +1,38 @@ +actingAs(User::factory()->create()) + ->get(route('home')) + ->assertRedirect(route('view-assets')); + } + + public function testUserCountIsScopedByCompany() + { + $this->markTestIncomplete(); + + $this->settings->enableMultipleFullCompanySupport(); + + $companyA = Company::factory()->has(User::factory()->count(1))->create(); + Company::factory()->has(User::factory()->count(3))->create(); + + $adminForCompanyA = $companyA->users()->save(User::factory()->admin()->make()); + + $this->actingAs($adminForCompanyA) + ->get(route('home')) + ->assertOk() + ->assertViewIs('dashboard') + ->assertViewHas('counts', fn($counts) => $counts['user'] === $companyA->users->count()); + } +} From efaed3d02cf48a8149d66f0a69c1a671d6811fe6 Mon Sep 17 00:00:00 2001 From: akemidx Date: Wed, 14 Jun 2023 15:32:47 -0400 Subject: [PATCH 13/56] making serial number logic checked against for new imports --- app/Importer/LicenseImporter.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/Importer/LicenseImporter.php b/app/Importer/LicenseImporter.php index 3bfbf1ee26..762ce6738c 100644 --- a/app/Importer/LicenseImporter.php +++ b/app/Importer/LicenseImporter.php @@ -31,7 +31,7 @@ class LicenseImporter extends ItemImporter public function createLicenseIfNotExists(array $row) { $editingLicense = false; - $license = License::where('name', $this->item['name']) + $license = License::where('serial', $this->item['serial']) ->first(); if ($license) { if (! $this->updating) { @@ -57,6 +57,10 @@ class LicenseImporter extends ItemImporter $this->item['maintained'] = $this->findCsvMatch($row, 'maintained'); $this->item['purchase_order'] = $this->findCsvMatch($row, 'purchase_order'); $this->item['reassignable'] = $this->findCsvMatch($row, 'reassignable'); + if($this->item['reassignable'] == "") + { + $this->item['reassignable'] = 1; + } $this->item['seats'] = $this->findCsvMatch($row, 'seats'); $this->item["termination_date"] = null; From df6b4ff349edeed6d7d6182d9f60811211318535 Mon Sep 17 00:00:00 2001 From: akemidx Date: Wed, 14 Jun 2023 15:51:14 -0400 Subject: [PATCH 14/56] tagging code --- app/Importer/LicenseImporter.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Importer/LicenseImporter.php b/app/Importer/LicenseImporter.php index 762ce6738c..4b3fec21fb 100644 --- a/app/Importer/LicenseImporter.php +++ b/app/Importer/LicenseImporter.php @@ -27,6 +27,9 @@ class LicenseImporter extends ItemImporter * @since 4.0 * @param array $row * @return License|mixed|null + * updated @author Jes Vinsmoke + * @since 6.1 + * */ public function createLicenseIfNotExists(array $row) { From eda5bbf3051f311b23d081c59cb96e45d6eb8739 Mon Sep 17 00:00:00 2001 From: akemidx Date: Thu, 15 Jun 2023 14:42:34 -0400 Subject: [PATCH 15/56] fix to allow empty SN --- app/Importer/LicenseImporter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Importer/LicenseImporter.php b/app/Importer/LicenseImporter.php index 4b3fec21fb..b943b1e863 100644 --- a/app/Importer/LicenseImporter.php +++ b/app/Importer/LicenseImporter.php @@ -34,7 +34,7 @@ class LicenseImporter extends ItemImporter public function createLicenseIfNotExists(array $row) { $editingLicense = false; - $license = License::where('serial', $this->item['serial']) + $license = License::where('serial', $this->item['serial'])->where('name', $this->item['name']) ->first(); if ($license) { if (! $this->updating) { From 00fd541963d5c241761f229e098e088a83610542 Mon Sep 17 00:00:00 2001 From: akemidx Date: Thu, 15 Jun 2023 15:09:14 -0400 Subject: [PATCH 16/56] improve logging clarity --- app/Importer/LicenseImporter.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/Importer/LicenseImporter.php b/app/Importer/LicenseImporter.php index b943b1e863..02ef05af5c 100644 --- a/app/Importer/LicenseImporter.php +++ b/app/Importer/LicenseImporter.php @@ -38,7 +38,13 @@ class LicenseImporter extends ItemImporter ->first(); if ($license) { if (! $this->updating) { - $this->log('A matching License '.$this->item['name'].' with serial '.$this->item['serial'].' already exists'); + + if($this->item['serial'] != "") { + $this->log('A matching License ' . $this->item['name'] . ' with serial ' . $this->item['serial'] . ' already exists'); + } + else { + $this->log('A matching License ' . $this->item['name'] . ' with no serial number already exists'); + } return; } From 65e8e4e1632cc009ff54b13b1d359f5a50595ca3 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 16:18:09 -0700 Subject: [PATCH 17/56] Guard against attempting to use invalid property --- tests/Support/InteractsWithResponses.php | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php index 3206aaea9d..9a1965eefe 100644 --- a/tests/Support/InteractsWithResponses.php +++ b/tests/Support/InteractsWithResponses.php @@ -4,16 +4,30 @@ namespace Tests\Support; use Illuminate\Database\Eloquent\Model; use Illuminate\Testing\TestResponse; +use RuntimeException; trait InteractsWithResponses { - private function assertResponseContainsInRows(TestResponse $response, Model $model, string $field = 'name') + protected function assertResponseContainsInRows(TestResponse $response, Model $model, string $property = 'name') { - $this->assertTrue(collect($response['rows'])->pluck($field)->contains($model->{$field})); + $this->guardAgainstNullProperty($model, $property); + + $this->assertTrue(collect($response['rows'])->pluck($property)->contains($model->{$property})); } - private function assertResponseDoesNotContainInRows(TestResponse $response, Model $model, string $field = 'name') + protected function assertResponseDoesNotContainInRows(TestResponse $response, Model $model, string $property = 'name') { - $this->assertFalse(collect($response['rows'])->pluck($field)->contains($model->{$field})); + $this->guardAgainstNullProperty($model, $property); + + $this->assertFalse(collect($response['rows'])->pluck($property)->contains($model->{$property})); + } + + private function guardAgainstNullProperty(Model $model, string $property): void + { + if (is_null($model->{$property})) { + throw new RuntimeException( + "The property ({$property}) is null on the model which isn't helpful for comparison." + ); + } } } From af77fefc61f09fe420a65f6232eefcdb408514b1 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 16:19:56 -0700 Subject: [PATCH 18/56] Scaffold test before removing scopeCompanyables call from AssetsController --- tests/Feature/Api/Assets/AssetIndexTest.php | 49 +++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/Feature/Api/Assets/AssetIndexTest.php b/tests/Feature/Api/Assets/AssetIndexTest.php index 3618c6e01e..9ca415c74d 100644 --- a/tests/Feature/Api/Assets/AssetIndexTest.php +++ b/tests/Feature/Api/Assets/AssetIndexTest.php @@ -3,14 +3,17 @@ 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\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetIndexTest extends TestCase { + use InteractsWithResponses; use InteractsWithSettings; public function testAssetIndexReturnsExpectedAssets() @@ -32,4 +35,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(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseDoesNotContainInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.assets.index')); + $this->assertResponseDoesNotContainInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + } } From fd55c99b87c5e68d524940a2fbfcad155cf0a8dc Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 16:29:44 -0700 Subject: [PATCH 19/56] Remove scopeCompanyables call from AssetsController@index --- app/Http/Controllers/Api/AssetsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index ced1f013c6..1169f652f2 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -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. From effd96928485cd342608d419e90dcaa2501e8dc3 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 17:15:02 -0700 Subject: [PATCH 20/56] Scaffold test before removing scopeCompanyables call from AssetsController@selectlist --- .../Api/Assets/AssetsForSelectListTest.php | 81 +++++++++++++++++++ tests/Support/InteractsWithResponses.php | 14 ++++ 2 files changed, 95 insertions(+) create mode 100644 tests/Feature/Api/Assets/AssetsForSelectListTest.php diff --git a/tests/Feature/Api/Assets/AssetsForSelectListTest.php b/tests/Feature/Api/Assets/AssetsForSelectListTest.php new file mode 100644 index 0000000000..625d623b76 --- /dev/null +++ b/tests/Feature/Api/Assets/AssetsForSelectListTest.php @@ -0,0 +1,81 @@ +create(['asset_tag' => '0001']); + Asset::factory()->create(['asset_tag' => '0002']); + + Passport::actingAs(User::factory()->create()); + + $response = $this->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() + { + $this->markTestIncomplete(); + + [$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(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseContainsInResults($response, $assetA); + $this->assertResponseDoesNotContainInResults($response, $assetB); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); + $this->assertResponseDoesNotContainInResults($response, $assetA); + $this->assertResponseContainsInResults($response, $assetB); + } +} diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php index 9a1965eefe..1fb6f311be 100644 --- a/tests/Support/InteractsWithResponses.php +++ b/tests/Support/InteractsWithResponses.php @@ -22,6 +22,20 @@ trait InteractsWithResponses $this->assertFalse(collect($response['rows'])->pluck($property)->contains($model->{$property})); } + protected function assertResponseContainsInResults(TestResponse $response, Model $model, string $property = 'id') + { + $this->guardAgainstNullProperty($model, $property); + + $this->assertTrue(collect($response->json('results'))->pluck('id')->contains($model->{$property})); + } + + protected function assertResponseDoesNotContainInResults(TestResponse $response, Model $model, string $property = 'id') + { + $this->guardAgainstNullProperty($model, $property); + + $this->assertFalse(collect($response->json('results'))->pluck('id')->contains($model->{$property})); + } + private function guardAgainstNullProperty(Model $model, string $property): void { if (is_null($model->{$property})) { From 0a5e1e31904f37c953ce75dfde23ac978c323f90 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 21 Jun 2023 17:21:36 -0700 Subject: [PATCH 21/56] Remove scopeCompanyables call from AssetsController@selectlist --- app/Http/Controllers/Api/AssetsController.php | 4 ++-- tests/Feature/Api/Assets/AssetsForSelectListTest.php | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 1169f652f2..e22a037a89 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -477,7 +477,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', @@ -485,7 +485,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(); diff --git a/tests/Feature/Api/Assets/AssetsForSelectListTest.php b/tests/Feature/Api/Assets/AssetsForSelectListTest.php index 625d623b76..fbc5a1e332 100644 --- a/tests/Feature/Api/Assets/AssetsForSelectListTest.php +++ b/tests/Feature/Api/Assets/AssetsForSelectListTest.php @@ -33,8 +33,6 @@ class AssetsForSelectListTest extends TestCase public function testAssetsAreScopedToCompanyWhenMultipleCompanySupportEnabled() { - $this->markTestIncomplete(); - [$companyA, $companyB] = Company::factory()->count(2)->create(); $assetA = Asset::factory()->for($companyA)->create(['asset_tag' => '0001']); From 74b072f1b5d68a0fa2289f0b7854926e17ea227e Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 12:36:30 -0700 Subject: [PATCH 22/56] Improve messaging in testing helper --- tests/Support/InteractsWithResponses.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php index 1fb6f311be..03faf0ef22 100644 --- a/tests/Support/InteractsWithResponses.php +++ b/tests/Support/InteractsWithResponses.php @@ -40,7 +40,7 @@ trait InteractsWithResponses { if (is_null($model->{$property})) { throw new RuntimeException( - "The property ({$property}) is null on the model which isn't helpful for comparison." + "The property ({$property}) either does not exist or is null on the model which isn't helpful for comparison." ); } } From ab5fed09dbe74263ffb92726772463278d0dfa84 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 12:36:43 -0700 Subject: [PATCH 23/56] Remove scopeCompanyables call from AssetsController@requestable --- app/Http/Controllers/Api/AssetsController.php | 5 +- database/factories/AssetFactory.php | 10 +++ .../Api/Assets/RequestableAssetsTest.php | 81 +++++++++++++++++++ 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 tests/Feature/Api/Assets/RequestableAssetsTest.php diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index e22a037a89..e3ae9e3445 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -1030,9 +1030,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); diff --git a/database/factories/AssetFactory.php b/database/factories/AssetFactory.php index cd3e0f8391..0e0c3931d8 100644 --- a/database/factories/AssetFactory.php +++ b/database/factories/AssetFactory.php @@ -328,4 +328,14 @@ class AssetFactory extends Factory ]; }); } + + public function requestable() + { + return $this->state(['requestable' => true]); + } + + public function nonrequestable() + { + return $this->state(['requestable' => false]); + } } diff --git a/tests/Feature/Api/Assets/RequestableAssetsTest.php b/tests/Feature/Api/Assets/RequestableAssetsTest.php new file mode 100644 index 0000000000..7c9b4e1204 --- /dev/null +++ b/tests/Feature/Api/Assets/RequestableAssetsTest.php @@ -0,0 +1,81 @@ +create()); + $this->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']); + + Passport::actingAs(User::factory()->viewRequestableAssets()->create()); + $response = $this->getJson(route('api.assets.requestable'))->assertOk(); + + $this->assertResponseContainsInRows($response, $requestableAsset, 'asset_tag'); + $this->assertResponseDoesNotContainInRows($response, $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(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + $this->settings->enableMultipleFullCompanySupport(); + + Passport::actingAs($superUser); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyA); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); + $this->assertResponseDoesNotContainInRows($response, $assetB, 'asset_tag'); + + Passport::actingAs($userInCompanyB); + $response = $this->getJson(route('api.assets.requestable')); + $this->assertResponseDoesNotContainInRows($response, $assetA, 'asset_tag'); + $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + } +} From a333d7b72fbaa56005316642fce584eda9eeb9a2 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 12:48:09 -0700 Subject: [PATCH 24/56] Add context to incomplete tests --- tests/Feature/Api/Departments/DepartmentsIndexTest.php | 4 +++- tests/Feature/Api/Users/UsersIndexTest.php | 4 +++- tests/Feature/DashboardTest.php | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php index d791c79e93..7e813ad9cb 100644 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -17,7 +17,9 @@ class DepartmentsIndexTest extends TestCase public function testDepartmentsIndexAdheresToCompanyScoping() { - $this->markTestIncomplete(); + $this->markTestIncomplete( + 'Waiting for removal of Company::scopeCompanyables in DepartmentsController@index' + ); [$companyA, $companyB] = Company::factory()->count(2)->create(); diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php index 16893cd174..b48da4483d 100644 --- a/tests/Feature/Api/Users/UsersIndexTest.php +++ b/tests/Feature/Api/Users/UsersIndexTest.php @@ -16,7 +16,9 @@ class UsersIndexTest extends TestCase public function testUsersIndexAdheresToCompanyScoping() { - $this->markTestIncomplete(); + $this->markTestIncomplete( + 'Waiting for removal of Company::scopeCompanyables in UsersController@index' + ); [$companyA, $companyB] = Company::factory()->count(2)->create(); diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index c5c41d268e..1772eac316 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -20,7 +20,9 @@ class DashboardTest extends TestCase public function testUserCountIsScopedByCompany() { - $this->markTestIncomplete(); + $this->markTestIncomplete( + 'Waiting for removal of Company::scopeCompanyables in DashboardController@index' + ); $this->settings->enableMultipleFullCompanySupport(); From a8133f62e81cc3bdd3aebb177515053c3d7e6e52 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 13:07:49 -0700 Subject: [PATCH 25/56] Add explicit select back to query --- app/Http/Controllers/Api/ConsumablesController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index 385f306c25..ba7e6fb302 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -45,7 +45,8 @@ class ConsumablesController extends Controller 'notes', ]; - $consumables = Consumable::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'))); From 8aae5beabafb6f58995bad31aa34359605ad1cfc Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 13:09:08 -0700 Subject: [PATCH 26/56] Add explicit select back to query --- app/Http/Controllers/Api/ComponentsController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index 59d12c920e..8b51344424 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -44,7 +44,8 @@ class ComponentsController extends Controller 'notes', ]; - $components = Component::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')); From a35d83d14a07d3bc1e7044be36c2e4af25f32c79 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 14:41:56 -0700 Subject: [PATCH 27/56] Migrate to response macros for readability --- tests/Feature/Api/Assets/AssetIndexTest.php | 38 +++++------ .../Api/Assets/AssetsForSelectListTest.php | 38 +++++------ .../Api/Assets/RequestableAssetsTest.php | 46 +++++++------ .../Api/Components/ComponentIndexTest.php | 38 +++++------ .../Api/Consumables/ConsumablesIndexTest.php | 38 +++++------ .../Api/Departments/DepartmentsIndexTest.php | 38 +++++------ .../Api/Licenses/LicensesIndexTest.php | 38 +++++------ tests/Feature/Api/Users/UsersIndexTest.php | 38 +++++------ tests/Support/CustomTestMacros.php | 66 +++++++++++++++++++ tests/Support/InteractsWithResponses.php | 47 ------------- tests/TestCase.php | 4 ++ 11 files changed, 218 insertions(+), 211 deletions(-) create mode 100644 tests/Support/CustomTestMacros.php delete mode 100644 tests/Support/InteractsWithResponses.php diff --git a/tests/Feature/Api/Assets/AssetIndexTest.php b/tests/Feature/Api/Assets/AssetIndexTest.php index 9ca415c74d..0fe3a4d306 100644 --- a/tests/Feature/Api/Assets/AssetIndexTest.php +++ b/tests/Feature/Api/Assets/AssetIndexTest.php @@ -7,13 +7,11 @@ use App\Models\Company; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testAssetIndexReturnsExpectedAssets() @@ -50,35 +48,35 @@ class AssetIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseDoesNotContainInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseDoesNotContainInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.assets.index')); - $this->assertResponseDoesNotContainInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.index')) + ->assertResponseDoesNotContainInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); } } diff --git a/tests/Feature/Api/Assets/AssetsForSelectListTest.php b/tests/Feature/Api/Assets/AssetsForSelectListTest.php index fbc5a1e332..a3210b9886 100644 --- a/tests/Feature/Api/Assets/AssetsForSelectListTest.php +++ b/tests/Feature/Api/Assets/AssetsForSelectListTest.php @@ -6,13 +6,11 @@ use App\Models\Asset; use App\Models\Company; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetsForSelectListTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testAssetsCanBeSearchedForByAssetTag() @@ -45,35 +43,35 @@ class AssetsForSelectListTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseContainsInResults($assetB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseContainsInResults($assetB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseContainsInResults($assetB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseContainsInResults($assetB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseContainsInResults($response, $assetA); - $this->assertResponseDoesNotContainInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseContainsInResults($assetA) + ->assertResponseDoesNotContainInResults($assetB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('assets.selectlist', ['search' => '000'])); - $this->assertResponseDoesNotContainInResults($response, $assetA); - $this->assertResponseContainsInResults($response, $assetB); + $this->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertResponseDoesNotContainInResults($assetA) + ->assertResponseContainsInResults($assetB); } } diff --git a/tests/Feature/Api/Assets/RequestableAssetsTest.php b/tests/Feature/Api/Assets/RequestableAssetsTest.php index 7c9b4e1204..7ecddeaa02 100644 --- a/tests/Feature/Api/Assets/RequestableAssetsTest.php +++ b/tests/Feature/Api/Assets/RequestableAssetsTest.php @@ -6,13 +6,11 @@ use App\Models\Asset; use App\Models\Company; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class RequestableAssetsTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testViewingRequestableAssetsRequiresCorrectPermission() @@ -27,10 +25,10 @@ class RequestableAssetsTest extends TestCase $nonRequestableAsset = Asset::factory()->nonrequestable()->create(['asset_tag' => 'non-requestable']); Passport::actingAs(User::factory()->viewRequestableAssets()->create()); - $response = $this->getJson(route('api.assets.requestable'))->assertOk(); - - $this->assertResponseContainsInRows($response, $requestableAsset, 'asset_tag'); - $this->assertResponseDoesNotContainInRows($response, $nonRequestableAsset, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertOk() + ->assertResponseContainsInRows($requestableAsset, 'asset_tag') + ->assertResponseDoesNotContainInRows($nonRequestableAsset, 'asset_tag'); } public function testRequestableAssetsAreScopedToCompanyWhenMultipleCompanySupportEnabled() @@ -47,35 +45,35 @@ class RequestableAssetsTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseContainsInRows($response, $assetA, 'asset_tag'); - $this->assertResponseDoesNotContainInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseContainsInRows($assetA, 'asset_tag') + ->assertResponseDoesNotContainInRows($assetB, 'asset_tag'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.assets.requestable')); - $this->assertResponseDoesNotContainInRows($response, $assetA, 'asset_tag'); - $this->assertResponseContainsInRows($response, $assetB, 'asset_tag'); + $this->getJson(route('api.assets.requestable')) + ->assertResponseDoesNotContainInRows($assetA, 'asset_tag') + ->assertResponseContainsInRows($assetB, 'asset_tag'); } } diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php index 845ce29b99..276f22e6f1 100644 --- a/tests/Feature/Api/Components/ComponentIndexTest.php +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -6,13 +6,11 @@ use App\Models\Company; use App\Models\Component; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ComponentIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testComponentIndexAdheresToCompanyScoping() @@ -29,35 +27,35 @@ class ComponentIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseContainsInRows($componentB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseContainsInRows($componentB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseContainsInRows($componentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseContainsInRows($componentB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseContainsInRows($response, $componentA); - $this->assertResponseDoesNotContainInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseContainsInRows($componentA) + ->assertResponseDoesNotContainInRows($componentB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.components.index')); - $this->assertResponseDoesNotContainInRows($response, $componentA); - $this->assertResponseContainsInRows($response, $componentB); + $this->getJson(route('api.components.index')) + ->assertResponseDoesNotContainInRows($componentA) + ->assertResponseContainsInRows($componentB); } } diff --git a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php index 11a4d79afa..6e6e809c6c 100644 --- a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php +++ b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php @@ -6,13 +6,11 @@ use App\Models\Company; use App\Models\Consumable; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ConsumablesIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testConsumableIndexAdheresToCompanyScoping() @@ -29,35 +27,35 @@ class ConsumablesIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseContainsInRows($consumableB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseContainsInRows($consumableB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseContainsInRows($consumableB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseContainsInRows($consumableB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseContainsInRows($response, $consumableA); - $this->assertResponseDoesNotContainInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseContainsInRows($consumableA) + ->assertResponseDoesNotContainInRows($consumableB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.consumables.index')); - $this->assertResponseDoesNotContainInRows($response, $consumableA); - $this->assertResponseContainsInRows($response, $consumableB); + $this->getJson(route('api.consumables.index')) + ->assertResponseDoesNotContainInRows($consumableA) + ->assertResponseContainsInRows($consumableB); } } diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php index 7e813ad9cb..9570e85307 100644 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -6,13 +6,11 @@ use App\Models\Company; use App\Models\Department; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class DepartmentsIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testDepartmentsIndexAdheresToCompanyScoping() @@ -33,35 +31,35 @@ class DepartmentsIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseContainsInRows($departmentB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseContainsInRows($departmentB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseContainsInRows($departmentB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseContainsInRows($departmentB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseContainsInRows($response, $departmentA); - $this->assertResponseDoesNotContainInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseContainsInRows($departmentA) + ->assertResponseDoesNotContainInRows($departmentB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.departments.index')); - $this->assertResponseDoesNotContainInRows($response, $departmentA); - $this->assertResponseContainsInRows($response, $departmentB); + $this->getJson(route('api.departments.index')) + ->assertResponseDoesNotContainInRows($departmentA) + ->assertResponseContainsInRows($departmentB); } } diff --git a/tests/Feature/Api/Licenses/LicensesIndexTest.php b/tests/Feature/Api/Licenses/LicensesIndexTest.php index 404eb31238..fd85239928 100644 --- a/tests/Feature/Api/Licenses/LicensesIndexTest.php +++ b/tests/Feature/Api/Licenses/LicensesIndexTest.php @@ -6,13 +6,11 @@ use App\Models\Company; use App\Models\License; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class LicensesIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testLicensesIndexAdheresToCompanyScoping() @@ -29,35 +27,35 @@ class LicensesIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseContainsInRows($licenseB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseContainsInRows($licenseB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseContainsInRows($licenseB); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseContainsInRows($licenseB); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseContainsInRows($response, $licenseA); - $this->assertResponseDoesNotContainInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseContainsInRows($licenseA) + ->assertResponseDoesNotContainInRows($licenseB); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.licenses.index')); - $this->assertResponseDoesNotContainInRows($response, $licenseA); - $this->assertResponseContainsInRows($response, $licenseB); + $this->getJson(route('api.licenses.index')) + ->assertResponseDoesNotContainInRows($licenseA) + ->assertResponseContainsInRows($licenseB); } } diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php index b48da4483d..ed91976ccb 100644 --- a/tests/Feature/Api/Users/UsersIndexTest.php +++ b/tests/Feature/Api/Users/UsersIndexTest.php @@ -5,13 +5,11 @@ namespace Tests\Feature\Api\Users; use App\Models\Company; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithResponses; use Tests\Support\InteractsWithSettings; use Tests\TestCase; class UsersIndexTest extends TestCase { - use InteractsWithResponses; use InteractsWithSettings; public function testUsersIndexAdheresToCompanyScoping() @@ -32,35 +30,35 @@ class UsersIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); $this->settings->enableMultipleFullCompanySupport(); Passport::actingAs($superUser); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); Passport::actingAs($userInCompanyA); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseContainsInRows($response, $userA, 'first_name'); - $this->assertResponseDoesNotContainInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseDoesNotContainInRows($userB, 'first_name'); Passport::actingAs($userInCompanyB); - $response = $this->getJson(route('api.users.index')); - $this->assertResponseDoesNotContainInRows($response, $userA, 'first_name'); - $this->assertResponseContainsInRows($response, $userB, 'first_name'); + $this->getJson(route('api.users.index')) + ->assertResponseDoesNotContainInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); } } diff --git a/tests/Support/CustomTestMacros.php b/tests/Support/CustomTestMacros.php new file mode 100644 index 0000000000..0a30d7c243 --- /dev/null +++ b/tests/Support/CustomTestMacros.php @@ -0,0 +1,66 @@ +{$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; + } + ); + } +} diff --git a/tests/Support/InteractsWithResponses.php b/tests/Support/InteractsWithResponses.php deleted file mode 100644 index 03faf0ef22..0000000000 --- a/tests/Support/InteractsWithResponses.php +++ /dev/null @@ -1,47 +0,0 @@ -guardAgainstNullProperty($model, $property); - - $this->assertTrue(collect($response['rows'])->pluck($property)->contains($model->{$property})); - } - - protected function assertResponseDoesNotContainInRows(TestResponse $response, Model $model, string $property = 'name') - { - $this->guardAgainstNullProperty($model, $property); - - $this->assertFalse(collect($response['rows'])->pluck($property)->contains($model->{$property})); - } - - protected function assertResponseContainsInResults(TestResponse $response, Model $model, string $property = 'id') - { - $this->guardAgainstNullProperty($model, $property); - - $this->assertTrue(collect($response->json('results'))->pluck('id')->contains($model->{$property})); - } - - protected function assertResponseDoesNotContainInResults(TestResponse $response, Model $model, string $property = 'id') - { - $this->guardAgainstNullProperty($model, $property); - - $this->assertFalse(collect($response->json('results'))->pluck('id')->contains($model->{$property})); - } - - private function guardAgainstNullProperty(Model $model, string $property): void - { - 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." - ); - } - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php index 28051c7c7f..4a5c3da692 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -5,11 +5,13 @@ 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\InteractsWithSettings; abstract class TestCase extends BaseTestCase { use CreatesApplication; + use CustomTestMacros; use LazilyRefreshDatabase; private array $globallyDisabledMiddleware = [ @@ -25,5 +27,7 @@ abstract class TestCase extends BaseTestCase if (collect(class_uses_recursive($this))->contains(InteractsWithSettings::class)) { $this->initializeSettings(); } + + $this->registerCustomMacros(); } } From acd06927ac09c32dd88773ec1bc9ca9782c5acf5 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 22 Jun 2023 17:37:30 -0700 Subject: [PATCH 28/56] Add helper method for authenticating with passport --- tests/Feature/Api/Assets/AssetIndexTest.php | 41 ++++++++-------- .../Api/Assets/AssetsForSelectListTest.php | 31 ++++++------ .../Api/Assets/RequestableAssetsTest.php | 34 ++++++------- .../Api/Components/ComponentIndexTest.php | 25 +++++----- .../Api/Consumables/ConsumablesIndexTest.php | 25 +++++----- .../Api/Departments/DepartmentsIndexTest.php | 25 +++++----- .../Api/Licenses/LicensesIndexTest.php | 25 +++++----- .../Api/Users/UsersForSelectListTest.php | 20 ++++---- tests/Feature/Api/Users/UsersIndexTest.php | 49 +++++++++---------- tests/Feature/Api/Users/UsersSearchTest.php | 6 +-- tests/Support/InteractsWithAuthentication.php | 16 ++++++ tests/TestCase.php | 2 + 12 files changed, 156 insertions(+), 143 deletions(-) create mode 100644 tests/Support/InteractsWithAuthentication.php diff --git a/tests/Feature/Api/Assets/AssetIndexTest.php b/tests/Feature/Api/Assets/AssetIndexTest.php index 0fe3a4d306..778483c1c9 100644 --- a/tests/Feature/Api/Assets/AssetIndexTest.php +++ b/tests/Feature/Api/Assets/AssetIndexTest.php @@ -6,7 +6,6 @@ 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; @@ -18,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', @@ -47,35 +46,35 @@ class AssetIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.assets.index')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseDoesNotContainInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.assets.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.assets.index')) ->assertResponseDoesNotContainInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); } diff --git a/tests/Feature/Api/Assets/AssetsForSelectListTest.php b/tests/Feature/Api/Assets/AssetsForSelectListTest.php index a3210b9886..cccae38d38 100644 --- a/tests/Feature/Api/Assets/AssetsForSelectListTest.php +++ b/tests/Feature/Api/Assets/AssetsForSelectListTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Assets; use App\Models\Asset; use App\Models\Company; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -18,9 +17,9 @@ class AssetsForSelectListTest extends TestCase Asset::factory()->create(['asset_tag' => '0001']); Asset::factory()->create(['asset_tag' => '0002']); - Passport::actingAs(User::factory()->create()); - - $response = $this->getJson(route('assets.selectlist', ['search' => '000']))->assertOk(); + $response = $this->actingAsForApi(User::factory()->create()) + ->getJson(route('assets.selectlist', ['search' => '000'])) + ->assertOk(); $results = collect($response->json('results')); @@ -42,35 +41,35 @@ class AssetsForSelectListTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($superUser) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseContainsInResults($assetB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseContainsInResults($assetB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseContainsInResults($assetB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($superUser) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseContainsInResults($assetB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseContainsInResults($assetA) ->assertResponseDoesNotContainInResults($assetB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('assets.selectlist', ['search' => '000'])) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('assets.selectlist', ['search' => '000'])) ->assertResponseDoesNotContainInResults($assetA) ->assertResponseContainsInResults($assetB); } diff --git a/tests/Feature/Api/Assets/RequestableAssetsTest.php b/tests/Feature/Api/Assets/RequestableAssetsTest.php index 7ecddeaa02..8649b1b00b 100644 --- a/tests/Feature/Api/Assets/RequestableAssetsTest.php +++ b/tests/Feature/Api/Assets/RequestableAssetsTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Assets; use App\Models\Asset; use App\Models\Company; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -15,8 +14,9 @@ class RequestableAssetsTest extends TestCase public function testViewingRequestableAssetsRequiresCorrectPermission() { - Passport::actingAs(User::factory()->create()); - $this->getJson(route('api.assets.requestable'))->assertForbidden(); + $this->actingAsForApi(User::factory()->create()) + ->getJson(route('api.assets.requestable')) + ->assertForbidden(); } public function testReturnsRequestableAssets() @@ -24,8 +24,8 @@ class RequestableAssetsTest extends TestCase $requestableAsset = Asset::factory()->requestable()->create(['asset_tag' => 'requestable']); $nonRequestableAsset = Asset::factory()->nonrequestable()->create(['asset_tag' => 'non-requestable']); - Passport::actingAs(User::factory()->viewRequestableAssets()->create()); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi(User::factory()->viewRequestableAssets()->create()) + ->getJson(route('api.assets.requestable')) ->assertOk() ->assertResponseContainsInRows($requestableAsset, 'asset_tag') ->assertResponseDoesNotContainInRows($nonRequestableAsset, 'asset_tag'); @@ -44,35 +44,35 @@ class RequestableAssetsTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($superUser) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($superUser) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.assets.requestable')) ->assertResponseContainsInRows($assetA, 'asset_tag') ->assertResponseDoesNotContainInRows($assetB, 'asset_tag'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.assets.requestable')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.assets.requestable')) ->assertResponseDoesNotContainInRows($assetA, 'asset_tag') ->assertResponseContainsInRows($assetB, 'asset_tag'); } diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php index 276f22e6f1..ee83b7a46d 100644 --- a/tests/Feature/Api/Components/ComponentIndexTest.php +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Components; use App\Models\Company; use App\Models\Component; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -26,35 +25,35 @@ class ComponentIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseContainsInRows($componentB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseContainsInRows($componentB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseContainsInRows($componentB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseContainsInRows($componentB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.components.index')) ->assertResponseContainsInRows($componentA) ->assertResponseDoesNotContainInRows($componentB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.components.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.components.index')) ->assertResponseDoesNotContainInRows($componentA) ->assertResponseContainsInRows($componentB); } diff --git a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php index 6e6e809c6c..33c10ed078 100644 --- a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php +++ b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Consumables; use App\Models\Company; use App\Models\Consumable; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -26,35 +25,35 @@ class ConsumablesIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseContainsInRows($consumableB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseContainsInRows($consumableB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseContainsInRows($consumableB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseContainsInRows($consumableB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.consumables.index')) ->assertResponseContainsInRows($consumableA) ->assertResponseDoesNotContainInRows($consumableB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.consumables.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.consumables.index')) ->assertResponseDoesNotContainInRows($consumableA) ->assertResponseContainsInRows($consumableB); } diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php index 9570e85307..1067ec74c7 100644 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ b/tests/Feature/Api/Departments/DepartmentsIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Departments; use App\Models\Company; use App\Models\Department; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -30,35 +29,35 @@ class DepartmentsIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseContainsInRows($departmentB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseContainsInRows($departmentB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseContainsInRows($departmentB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseContainsInRows($departmentB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.departments.index')) ->assertResponseContainsInRows($departmentA) ->assertResponseDoesNotContainInRows($departmentB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.departments.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.departments.index')) ->assertResponseDoesNotContainInRows($departmentA) ->assertResponseContainsInRows($departmentB); } diff --git a/tests/Feature/Api/Licenses/LicensesIndexTest.php b/tests/Feature/Api/Licenses/LicensesIndexTest.php index fd85239928..a21a27da73 100644 --- a/tests/Feature/Api/Licenses/LicensesIndexTest.php +++ b/tests/Feature/Api/Licenses/LicensesIndexTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Licenses; use App\Models\Company; use App\Models\License; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -26,35 +25,35 @@ class LicensesIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseContainsInRows($licenseB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseContainsInRows($licenseB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseContainsInRows($licenseB); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($superUser) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseContainsInRows($licenseB); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.licenses.index')) ->assertResponseContainsInRows($licenseA) ->assertResponseDoesNotContainInRows($licenseB); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.licenses.index')) + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.licenses.index')) ->assertResponseDoesNotContainInRows($licenseA) ->assertResponseContainsInRows($licenseB); } diff --git a/tests/Feature/Api/Users/UsersForSelectListTest.php b/tests/Feature/Api/Users/UsersForSelectListTest.php index 8cdf700f04..ba4beb211b 100644 --- a/tests/Feature/Api/Users/UsersForSelectListTest.php +++ b/tests/Feature/Api/Users/UsersForSelectListTest.php @@ -5,7 +5,6 @@ namespace Tests\Feature\Api\Users; 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,8 +16,8 @@ class UsersForSelectListTest extends TestCase { $users = User::factory()->superuser()->count(3)->create(); - Passport::actingAs($users->first()); - $this->getJson(route('api.users.selectlist')) + $this->actingAsForApi($users->first()) + ->getJson(route('api.users.selectlist')) ->assertOk() ->assertJsonStructure([ 'results', @@ -34,8 +33,9 @@ class UsersForSelectListTest extends TestCase { User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']); - Passport::actingAs(User::factory()->create()); - $response = $this->getJson(route('api.users.selectlist', ['search' => 'luke sky']))->assertOk(); + $response = $this->actingAsForApi(User::factory()->create()) + ->getJson(route('api.users.selectlist', ['search' => 'luke sky'])) + ->assertOk(); $results = collect($response->json('results')); @@ -57,8 +57,9 @@ class UsersForSelectListTest extends TestCase ->has(User::factory()->state(['first_name' => 'Darth', 'last_name' => 'Vader', 'username' => 'dvader'])) ->create(); - Passport::actingAs($jedi->users->first()); - $response = $this->getJson(route('api.users.selectlist'))->assertOk(); + $response = $this->actingAsForApi($jedi->users->first()) + ->getJson(route('api.users.selectlist')) + ->assertOk(); $results = collect($response->json('results')); @@ -85,8 +86,9 @@ class UsersForSelectListTest extends TestCase ->has(User::factory()->state(['first_name' => 'Darth', 'last_name' => 'Vader', 'username' => 'dvader'])) ->create(); - Passport::actingAs($jedi->users->first()); - $response = $this->getJson(route('api.users.selectlist', ['search' => 'a']))->assertOk(); + $response = $this->actingAsForApi($jedi->users->first()) + ->getJson(route('api.users.selectlist', ['search' => 'a'])) + ->assertOk(); $results = collect($response->json('results')); diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php index ed91976ccb..644c5e9e0d 100644 --- a/tests/Feature/Api/Users/UsersIndexTest.php +++ b/tests/Feature/Api/Users/UsersIndexTest.php @@ -4,7 +4,6 @@ namespace Tests\Feature\Api\Users; use App\Models\Company; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -29,36 +28,36 @@ class UsersIndexTest extends TestCase $this->settings->disableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($superUser) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); $this->settings->enableMultipleFullCompanySupport(); - Passport::actingAs($superUser); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($superUser) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); - Passport::actingAs($userInCompanyA); - $this->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseDoesNotContainInRows($userB, 'first_name'); + $this->actingAsForApi($userInCompanyA) + ->getJson(route('api.users.index')) + ->assertResponseContainsInRows($userA, 'first_name') + ->assertResponseDoesNotContainInRows($userB, 'first_name'); - Passport::actingAs($userInCompanyB); - $this->getJson(route('api.users.index')) - ->assertResponseDoesNotContainInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); + $this->actingAsForApi($userInCompanyB) + ->getJson(route('api.users.index')) + ->assertResponseDoesNotContainInRows($userA, 'first_name') + ->assertResponseContainsInRows($userB, 'first_name'); } } diff --git a/tests/Feature/Api/Users/UsersSearchTest.php b/tests/Feature/Api/Users/UsersSearchTest.php index 33f77196f3..349cd1e85c 100644 --- a/tests/Feature/Api/Users/UsersSearchTest.php +++ b/tests/Feature/Api/Users/UsersSearchTest.php @@ -3,7 +3,6 @@ namespace Tests\Feature\Api\Users; use App\Models\User; -use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -16,8 +15,9 @@ class UsersSearchTest extends TestCase User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']); User::factory()->create(['first_name' => 'Darth', 'last_name' => 'Vader']); - Passport::actingAs(User::factory()->viewUsers()->create()); - $response = $this->getJson(route('api.users.index', ['search' => 'luke sky']))->assertOk(); + $response = $this->actingAsForApi(User::factory()->viewUsers()->create()) + ->getJson(route('api.users.index', ['search' => 'luke sky'])) + ->assertOk(); $results = collect($response->json('rows')); diff --git a/tests/Support/InteractsWithAuthentication.php b/tests/Support/InteractsWithAuthentication.php new file mode 100644 index 0000000000..27b20e382b --- /dev/null +++ b/tests/Support/InteractsWithAuthentication.php @@ -0,0 +1,16 @@ + Date: Mon, 26 Jun 2023 11:26:46 -0700 Subject: [PATCH 29/56] adds half_year fix from jdickerson71388 --- app/Models/Depreciable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Depreciable.php b/app/Models/Depreciable.php index 250894820c..9bbf4fcbf8 100644 --- a/app/Models/Depreciable.php +++ b/app/Models/Depreciable.php @@ -127,7 +127,7 @@ class Depreciable extends SnipeModel $yearsPast = 0; } - return round($yearsPast / $deprecationYears * $this->purchase_cost, 2); + return $this->purchase_cost - round($yearsPast / $deprecationYears * $this->purchase_cost, 2); } /** From 7cb22d3d49b1b8707f8f44f09e39c4aba28d2670 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 26 Jun 2023 14:00:53 -0700 Subject: [PATCH 30/56] Remove incomplete tests --- .../Api/Departments/DepartmentsIndexTest.php | 64 ------------------- tests/Feature/Api/Users/UsersIndexTest.php | 63 ------------------ tests/Feature/DashboardTest.php | 21 ------ 3 files changed, 148 deletions(-) delete mode 100644 tests/Feature/Api/Departments/DepartmentsIndexTest.php delete mode 100644 tests/Feature/Api/Users/UsersIndexTest.php diff --git a/tests/Feature/Api/Departments/DepartmentsIndexTest.php b/tests/Feature/Api/Departments/DepartmentsIndexTest.php deleted file mode 100644 index 1067ec74c7..0000000000 --- a/tests/Feature/Api/Departments/DepartmentsIndexTest.php +++ /dev/null @@ -1,64 +0,0 @@ -markTestIncomplete( - 'Waiting for removal of Company::scopeCompanyables in DepartmentsController@index' - ); - - [$companyA, $companyB] = Company::factory()->count(2)->create(); - - $departmentA = Department::factory()->for($companyA)->create(); - $departmentB = Department::factory()->for($companyB)->create(); - - $superUser = $companyA->users()->save(User::factory()->superuser()->make()); - $userInCompanyA = $companyA->users()->save(User::factory()->viewDepartments()->make()); - $userInCompanyB = $companyB->users()->save(User::factory()->viewDepartments()->make()); - - $this->settings->disableMultipleFullCompanySupport(); - - $this->actingAsForApi($superUser) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - - $this->actingAsForApi($userInCompanyA) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - - $this->actingAsForApi($userInCompanyB) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - - $this->settings->enableMultipleFullCompanySupport(); - - $this->actingAsForApi($superUser) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - - $this->actingAsForApi($userInCompanyA) - ->getJson(route('api.departments.index')) - ->assertResponseContainsInRows($departmentA) - ->assertResponseDoesNotContainInRows($departmentB); - - $this->actingAsForApi($userInCompanyB) - ->getJson(route('api.departments.index')) - ->assertResponseDoesNotContainInRows($departmentA) - ->assertResponseContainsInRows($departmentB); - } -} diff --git a/tests/Feature/Api/Users/UsersIndexTest.php b/tests/Feature/Api/Users/UsersIndexTest.php deleted file mode 100644 index 644c5e9e0d..0000000000 --- a/tests/Feature/Api/Users/UsersIndexTest.php +++ /dev/null @@ -1,63 +0,0 @@ -markTestIncomplete( - 'Waiting for removal of Company::scopeCompanyables in UsersController@index' - ); - - [$companyA, $companyB] = Company::factory()->count(2)->create(); - - $userA = User::factory()->for($companyA)->create(); - $userB = User::factory()->for($companyB)->create(); - - $superUser = $companyA->users()->save(User::factory()->superuser()->make()); - $userInCompanyA = $companyA->users()->save(User::factory()->viewUsers()->make()); - $userInCompanyB = $companyB->users()->save(User::factory()->viewUsers()->make()); - - $this->settings->disableMultipleFullCompanySupport(); - - $this->actingAsForApi($superUser) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - - $this->actingAsForApi($userInCompanyA) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - - $this->actingAsForApi($userInCompanyB) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - - $this->settings->enableMultipleFullCompanySupport(); - - $this->actingAsForApi($superUser) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - - $this->actingAsForApi($userInCompanyA) - ->getJson(route('api.users.index')) - ->assertResponseContainsInRows($userA, 'first_name') - ->assertResponseDoesNotContainInRows($userB, 'first_name'); - - $this->actingAsForApi($userInCompanyB) - ->getJson(route('api.users.index')) - ->assertResponseDoesNotContainInRows($userA, 'first_name') - ->assertResponseContainsInRows($userB, 'first_name'); - } -} diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index 1772eac316..4e9459fb06 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -2,7 +2,6 @@ namespace Tests\Feature; -use App\Models\Company; use App\Models\User; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -17,24 +16,4 @@ class DashboardTest extends TestCase ->get(route('home')) ->assertRedirect(route('view-assets')); } - - public function testUserCountIsScopedByCompany() - { - $this->markTestIncomplete( - 'Waiting for removal of Company::scopeCompanyables in DashboardController@index' - ); - - $this->settings->enableMultipleFullCompanySupport(); - - $companyA = Company::factory()->has(User::factory()->count(1))->create(); - Company::factory()->has(User::factory()->count(3))->create(); - - $adminForCompanyA = $companyA->users()->save(User::factory()->admin()->make()); - - $this->actingAs($adminForCompanyA) - ->get(route('home')) - ->assertOk() - ->assertViewIs('dashboard') - ->assertViewHas('counts', fn($counts) => $counts['user'] === $companyA->users->count()); - } } From 2abdb8a5fd02ab2c5dff8e6e3dd22f5a1c9d5751 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 26 Jun 2023 14:01:09 -0700 Subject: [PATCH 31/56] Revert unneeded changes --- .../Api/Users/UsersForSelectListTest.php | 20 +++++++++---------- tests/Feature/Api/Users/UsersSearchTest.php | 6 +++--- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/tests/Feature/Api/Users/UsersForSelectListTest.php b/tests/Feature/Api/Users/UsersForSelectListTest.php index ba4beb211b..8cdf700f04 100644 --- a/tests/Feature/Api/Users/UsersForSelectListTest.php +++ b/tests/Feature/Api/Users/UsersForSelectListTest.php @@ -5,6 +5,7 @@ namespace Tests\Feature\Api\Users; use App\Models\Company; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; +use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -16,8 +17,8 @@ class UsersForSelectListTest extends TestCase { $users = User::factory()->superuser()->count(3)->create(); - $this->actingAsForApi($users->first()) - ->getJson(route('api.users.selectlist')) + Passport::actingAs($users->first()); + $this->getJson(route('api.users.selectlist')) ->assertOk() ->assertJsonStructure([ 'results', @@ -33,9 +34,8 @@ class UsersForSelectListTest extends TestCase { User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']); - $response = $this->actingAsForApi(User::factory()->create()) - ->getJson(route('api.users.selectlist', ['search' => 'luke sky'])) - ->assertOk(); + Passport::actingAs(User::factory()->create()); + $response = $this->getJson(route('api.users.selectlist', ['search' => 'luke sky']))->assertOk(); $results = collect($response->json('results')); @@ -57,9 +57,8 @@ class UsersForSelectListTest extends TestCase ->has(User::factory()->state(['first_name' => 'Darth', 'last_name' => 'Vader', 'username' => 'dvader'])) ->create(); - $response = $this->actingAsForApi($jedi->users->first()) - ->getJson(route('api.users.selectlist')) - ->assertOk(); + Passport::actingAs($jedi->users->first()); + $response = $this->getJson(route('api.users.selectlist'))->assertOk(); $results = collect($response->json('results')); @@ -86,9 +85,8 @@ class UsersForSelectListTest extends TestCase ->has(User::factory()->state(['first_name' => 'Darth', 'last_name' => 'Vader', 'username' => 'dvader'])) ->create(); - $response = $this->actingAsForApi($jedi->users->first()) - ->getJson(route('api.users.selectlist', ['search' => 'a'])) - ->assertOk(); + Passport::actingAs($jedi->users->first()); + $response = $this->getJson(route('api.users.selectlist', ['search' => 'a']))->assertOk(); $results = collect($response->json('results')); diff --git a/tests/Feature/Api/Users/UsersSearchTest.php b/tests/Feature/Api/Users/UsersSearchTest.php index 349cd1e85c..33f77196f3 100644 --- a/tests/Feature/Api/Users/UsersSearchTest.php +++ b/tests/Feature/Api/Users/UsersSearchTest.php @@ -3,6 +3,7 @@ namespace Tests\Feature\Api\Users; use App\Models\User; +use Laravel\Passport\Passport; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -15,9 +16,8 @@ class UsersSearchTest extends TestCase User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']); User::factory()->create(['first_name' => 'Darth', 'last_name' => 'Vader']); - $response = $this->actingAsForApi(User::factory()->viewUsers()->create()) - ->getJson(route('api.users.index', ['search' => 'luke sky'])) - ->assertOk(); + Passport::actingAs(User::factory()->viewUsers()->create()); + $response = $this->getJson(route('api.users.index', ['search' => 'luke sky']))->assertOk(); $results = collect($response->json('rows')); From 3f09e6017b444f4c0578b83c16f1226d37f1787c Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Mon, 26 Jun 2023 16:22:28 -0700 Subject: [PATCH 32/56] Install paratest to allow for parallel test running --- composer.json | 1 + composer.lock | 156 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 155 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 165a4a08f6..cf4a524376 100644 --- a/composer.json +++ b/composer.json @@ -74,6 +74,7 @@ "watson/validating": "^6.1" }, "require-dev": { + "brianium/paratest": "^6.6", "fakerphp/faker": "^1.16", "laravel/dusk": "^6.25", "mockery/mockery": "^1.4", diff --git a/composer.lock b/composer.lock index 1ef75690aa..4e522d8a99 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4c82b2e171fb02a3ef024906db5d74c9", + "content-hash": "217a3619f0f4eebdb280299efdd7297e", "packages": [ { "name": "alek13/slack", @@ -12122,6 +12122,99 @@ ], "time": "2021-03-30T17:13:30+00:00" }, + { + "name": "brianium/paratest", + "version": "v6.6.2", + "source": { + "type": "git", + "url": "https://github.com/paratestphp/paratest.git", + "reference": "5249af4e25e79da66d1ec3b54b474047999c10b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/5249af4e25e79da66d1ec3b54b474047999c10b8", + "reference": "5249af4e25e79da66d1ec3b54b474047999c10b8", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-simplexml": "*", + "jean85/pretty-package-versions": "^2.0.5", + "php": "^7.3 || ^8.0", + "phpunit/php-code-coverage": "^9.2.15", + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-timer": "^5.0.3", + "phpunit/phpunit": "^9.5.21", + "sebastian/environment": "^5.1.4", + "symfony/console": "^5.4.9 || ^6.1.2", + "symfony/polyfill-php80": "^v1.26.0", + "symfony/process": "^5.4.8 || ^6.1.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0.0", + "ext-pcov": "*", + "ext-posix": "*", + "infection/infection": "^0.26.13", + "malukenho/mcbumpface": "^1.1.5", + "squizlabs/php_codesniffer": "^3.7.1", + "symfony/filesystem": "^5.4.9 || ^6.1.0", + "vimeo/psalm": "^4.26.0" + }, + "bin": [ + "bin/paratest", + "bin/paratest.bat", + "bin/paratest_for_phpstorm" + ], + "type": "library", + "autoload": { + "psr-4": { + "ParaTest\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Scaturro", + "email": "scaturrob@gmail.com", + "role": "Developer" + }, + { + "name": "Filippo Tessarotto", + "email": "zoeslam@gmail.com", + "role": "Developer" + } + ], + "description": "Parallel testing for PHP", + "homepage": "https://github.com/paratestphp/paratest", + "keywords": [ + "concurrent", + "parallel", + "phpunit", + "testing" + ], + "support": { + "issues": "https://github.com/paratestphp/paratest/issues", + "source": "https://github.com/paratestphp/paratest/tree/v6.6.2" + }, + "funding": [ + { + "url": "https://github.com/sponsors/Slamdunk", + "type": "github" + }, + { + "url": "https://paypal.me/filippotessarotto", + "type": "paypal" + } + ], + "time": "2022-08-22T10:45:51+00:00" + }, { "name": "composer/ca-bundle", "version": "1.3.5", @@ -13232,6 +13325,65 @@ }, "time": "2020-07-09T08:09:16+00:00" }, + { + "name": "jean85/pretty-package-versions", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0.0", + "php": "^7.1|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.17", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7.5|^8.5|^9.4", + "vimeo/psalm": "^4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" + }, + "time": "2021-10-08T21:21:46+00:00" + }, { "name": "justinrainbow/json-schema", "version": "5.2.12", @@ -16570,5 +16722,5 @@ "ext-pdo": "*" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.3.0" } From 62347a56ba1dc57cb233068b375af377ac4a117b Mon Sep 17 00:00:00 2001 From: Ivan Nieto Vivanco Date: Tue, 27 Jun 2023 16:41:30 -0600 Subject: [PATCH 33/56] Add button with cancel action in requested assets view --- resources/views/hardware/requested.blade.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/resources/views/hardware/requested.blade.php b/resources/views/hardware/requested.blade.php index 25b2a51e28..36bcd74040 100644 --- a/resources/views/hardware/requested.blade.php +++ b/resources/views/hardware/requested.blade.php @@ -24,7 +24,7 @@ 'id' => 'bulkForm']) }}
    - + {{ Form::close() }} @if ($requestedItems->count() > 0)
    {{ trans('admin/hardware/form.expected_checkin') }} - + @@ -103,6 +103,9 @@ @endif +
    {{ trans('admin/hardware/table.requesting_user') }} {{ trans('admin/hardware/table.requested_date') }}{{ trans('general.checkin').'/'.trans('general.checkout') }}{{ trans('button.actions') }}
    {{ App\Helpers\Helper::getFormattedDateObject($request->created_at, 'datetime', false) }} +
    @csrf
    +
    @if ($request->itemType() == "asset") @if ($request->requestable->assigned_to=='') From b647a8fcd242ba7821badf9165ea71d09e25a07b Mon Sep 17 00:00:00 2001 From: Ivan Nieto Vivanco Date: Tue, 27 Jun 2023 17:02:25 -0600 Subject: [PATCH 34/56] Change the inline form HTML label to the Form:: facade --- resources/views/hardware/requested.blade.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/resources/views/hardware/requested.blade.php b/resources/views/hardware/requested.blade.php index 36bcd74040..beccf44725 100644 --- a/resources/views/hardware/requested.blade.php +++ b/resources/views/hardware/requested.blade.php @@ -104,7 +104,12 @@ {{ App\Helpers\Helper::getFormattedDateObject($request->created_at, 'datetime', false) }} -
    @csrf
    + {{ Form::open([ + 'method' => 'POST', + 'route' => ['account/request-asset', $request->requestable->id], + ]) }} + + {{ Form::close() }}
    @if ($request->itemType() == "asset") From eb4d7646015fe00ed9a499299e3aaa3945ae20cb Mon Sep 17 00:00:00 2001 From: Ivan Nieto Vivanco Date: Tue, 27 Jun 2023 17:13:11 -0600 Subject: [PATCH 35/56] Refactor Requestable@cancelRequest() firm to admit a user_id so we can cancel a request of whatever user we want --- app/Models/Requestable.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/Models/Requestable.php b/app/Models/Requestable.php index 3983254e41..bf5c9c427b 100644 --- a/app/Models/Requestable.php +++ b/app/Models/Requestable.php @@ -38,8 +38,12 @@ trait Requestable $this->requests()->where('user_id', Auth::id())->delete(); } - public function cancelRequest() + public function cancelRequest($user_id = null) { - $this->requests()->where('user_id', Auth::id())->update(['canceled_at' => \Carbon\Carbon::now()]); + if (!$user_id){ + $user_id = Auth::id(); + } + + $this->requests()->where('user_id', $user_id)->update(['canceled_at' => \Carbon\Carbon::now()]); } } From 1c29bd37a69b3129e62dcc3ee97bca7869eee652 Mon Sep 17 00:00:00 2001 From: Ivan Nieto Vivanco Date: Tue, 27 Jun 2023 18:11:10 -0600 Subject: [PATCH 36/56] Added feature to cancel requests from the Requested Assets view --- app/Http/Controllers/ViewAssetsController.php | 6 +++--- resources/views/hardware/requested.blade.php | 2 +- routes/web.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/ViewAssetsController.php b/app/Http/Controllers/ViewAssetsController.php index ee3e4b14c6..f8f72ea3a8 100755 --- a/app/Http/Controllers/ViewAssetsController.php +++ b/app/Http/Controllers/ViewAssetsController.php @@ -82,7 +82,7 @@ class ViewAssetsController extends Controller return view('account/requestable-assets', compact('assets', 'models')); } - public function getRequestItem(Request $request, $itemType, $itemId = null) + public function getRequestItem(Request $request, $itemType, $itemId = null, $cancel_by_admin = false, $requestingUser = null) { $item = null; $fullItemType = 'App\\Models\\'.studly_case($itemType); @@ -119,8 +119,8 @@ class ViewAssetsController extends Controller $settings = Setting::getSettings(); - if ($item_request = $item->isRequestedBy($user)) { - $item->cancelRequest(); + if (($item_request = $item->isRequestedBy($user)) || $cancel_by_admin) { + $item->cancelRequest($requestingUser); $data['item_quantity'] = $item_request->qty; $logaction->logaction('request_canceled'); diff --git a/resources/views/hardware/requested.blade.php b/resources/views/hardware/requested.blade.php index beccf44725..25502b42c3 100644 --- a/resources/views/hardware/requested.blade.php +++ b/resources/views/hardware/requested.blade.php @@ -106,7 +106,7 @@ {{ Form::open([ 'method' => 'POST', - 'route' => ['account/request-asset', $request->requestable->id], + 'route' => ['account/request-item', $request->itemType(), $request->requestable->id, true, $request->requestingUser()->id], ]) }} {{ Form::close() }} diff --git a/routes/web.php b/routes/web.php index 49998f43fc..5de6ef9025 100644 --- a/routes/web.php +++ b/routes/web.php @@ -281,7 +281,7 @@ Route::group(['prefix' => 'account', 'middleware' => ['auth']], function () { )->name('account/request-asset'); Route::post( - 'request/{itemType}/{itemId}', + 'request/{itemType}/{itemId}/{cancel_by_admin?}/{requestingUser?}', [ViewAssetsController::class, 'getRequestItem'] )->name('account/request-item'); From b4b84f91d0020dfa695dfc263fa2ebc510eff2e6 Mon Sep 17 00:00:00 2001 From: Ivan Nieto Vivanco Date: Tue, 27 Jun 2023 18:25:38 -0600 Subject: [PATCH 37/56] Redirect to correct page after cancel action --- app/Http/Controllers/ViewAssetsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/ViewAssetsController.php b/app/Http/Controllers/ViewAssetsController.php index f8f72ea3a8..a759ca1978 100755 --- a/app/Http/Controllers/ViewAssetsController.php +++ b/app/Http/Controllers/ViewAssetsController.php @@ -128,7 +128,7 @@ class ViewAssetsController extends Controller $settings->notify(new RequestAssetCancelation($data)); } - return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.canceled')); + return redirect()->back()->with('success')->with('success', trans('admin/hardware/message.requests.canceled')); } else { $item->request(); if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) { From 8496e64e16daf779b9dedcb775232ea3901aa546 Mon Sep 17 00:00:00 2001 From: Ivan Nieto Vivanco Date: Tue, 27 Jun 2023 18:37:22 -0600 Subject: [PATCH 38/56] Adds ternary to set a quantity when needed --- app/Http/Controllers/ViewAssetsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/ViewAssetsController.php b/app/Http/Controllers/ViewAssetsController.php index a759ca1978..c9aafd2c78 100755 --- a/app/Http/Controllers/ViewAssetsController.php +++ b/app/Http/Controllers/ViewAssetsController.php @@ -121,7 +121,7 @@ class ViewAssetsController extends Controller if (($item_request = $item->isRequestedBy($user)) || $cancel_by_admin) { $item->cancelRequest($requestingUser); - $data['item_quantity'] = $item_request->qty; + $data['item_quantity'] = ($item_request) ? $item_request->qty : 1; $logaction->logaction('request_canceled'); if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) { From 8d8adc16397eac98e98dd0c628309094b79b6979 Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 28 Jun 2023 15:02:32 +0100 Subject: [PATCH 39/56] Use the Helper::parseEscapedMarkedown in notes Signed-off-by: snipe --- app/Http/Transformers/AccessoriesTransformer.php | 2 +- app/Http/Transformers/ActionlogsTransformer.php | 2 +- app/Http/Transformers/AssetMaintenancesTransformer.php | 2 +- app/Http/Transformers/AssetModelsTransformer.php | 2 +- app/Http/Transformers/AssetsTransformer.php | 2 +- app/Http/Transformers/ComponentsTransformer.php | 2 +- app/Http/Transformers/ConsumablesTransformer.php | 2 +- app/Http/Transformers/LicensesTransformer.php | 2 +- app/Http/Transformers/SuppliersTransformer.php | 2 +- app/Http/Transformers/UsersTransformer.php | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/Http/Transformers/AccessoriesTransformer.php b/app/Http/Transformers/AccessoriesTransformer.php index cdc94ebed9..709b337c93 100644 --- a/app/Http/Transformers/AccessoriesTransformer.php +++ b/app/Http/Transformers/AccessoriesTransformer.php @@ -32,7 +32,7 @@ class AccessoriesTransformer 'model_number' => ($accessory->model_number) ? e($accessory->model_number) : null, 'category' => ($accessory->category) ? ['id' => $accessory->category->id, 'name'=> e($accessory->category->name)] : null, 'location' => ($accessory->location) ? ['id' => $accessory->location->id, 'name'=> e($accessory->location->name)] : null, - 'notes' => ($accessory->notes) ? e($accessory->notes) : null, + 'notes' => ($accessory->notes) ? Helper::parseEscapedMarkedown($accessory->notes) : null, 'qty' => ($accessory->qty) ? (int) $accessory->qty : null, 'purchase_date' => ($accessory->purchase_date) ? Helper::getFormattedDateObject($accessory->purchase_date, 'date') : null, 'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost), diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php index cd2ce586d1..ab756a4dd3 100644 --- a/app/Http/Transformers/ActionlogsTransformer.php +++ b/app/Http/Transformers/ActionlogsTransformer.php @@ -110,7 +110,7 @@ class ActionlogsTransformer 'type' => e($actionlog->targetType()), ] : null, - 'note' => ($actionlog->note) ? e($actionlog->note): null, + 'note' => ($actionlog->note) ? Helper::parseEscapedMarkedown($actionlog->note): null, 'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null, 'log_meta' => ((isset($clean_meta)) && (is_array($clean_meta))) ? $clean_meta: null, 'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'), diff --git a/app/Http/Transformers/AssetMaintenancesTransformer.php b/app/Http/Transformers/AssetMaintenancesTransformer.php index 10b05b33af..433c06a49d 100644 --- a/app/Http/Transformers/AssetMaintenancesTransformer.php +++ b/app/Http/Transformers/AssetMaintenancesTransformer.php @@ -49,7 +49,7 @@ class AssetMaintenancesTransformer 'id' => (int) $assetmaintenance->asset->defaultLoc->id, 'name'=> e($assetmaintenance->asset->defaultLoc->name), ] : null, - 'notes' => ($assetmaintenance->notes) ? e($assetmaintenance->notes) : null, + 'notes' => ($assetmaintenance->notes) ? Helper::parseEscapedMarkedown($assetmaintenance->notes) : null, 'supplier' => ($assetmaintenance->supplier) ? ['id' => $assetmaintenance->supplier->id, 'name'=> e($assetmaintenance->supplier->name)] : null, 'cost' => Helper::formatCurrencyOutput($assetmaintenance->cost), 'asset_maintenance_type' => e($assetmaintenance->asset_maintenance_type), diff --git a/app/Http/Transformers/AssetModelsTransformer.php b/app/Http/Transformers/AssetModelsTransformer.php index 5725e55930..a2da6c8b42 100644 --- a/app/Http/Transformers/AssetModelsTransformer.php +++ b/app/Http/Transformers/AssetModelsTransformer.php @@ -63,7 +63,7 @@ class AssetModelsTransformer 'default_fieldset_values' => $default_field_values, 'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None', 'requestable' => ($assetmodel->requestable == '1') ? true : false, - 'notes' => e($assetmodel->notes), + 'notes' => Helper::parseEscapedMarkedown($assetmodel->notes), 'created_at' => Helper::getFormattedDateObject($assetmodel->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($assetmodel->updated_at, 'datetime'), 'deleted_at' => Helper::getFormattedDateObject($assetmodel->deleted_at, 'datetime'), diff --git a/app/Http/Transformers/AssetsTransformer.php b/app/Http/Transformers/AssetsTransformer.php index 85f5f9294d..0ad93b43ef 100644 --- a/app/Http/Transformers/AssetsTransformer.php +++ b/app/Http/Transformers/AssetsTransformer.php @@ -58,7 +58,7 @@ class AssetsTransformer 'id' => (int) $asset->supplier->id, 'name'=> e($asset->supplier->name), ] : null, - 'notes' => ($asset->notes) ? e($asset->notes) : null, + 'notes' => ($asset->notes) ? Helper::parseEscapedMarkedown($asset->notes) : null, 'order_number' => ($asset->order_number) ? e($asset->order_number) : null, 'company' => ($asset->company) ? [ 'id' => (int) $asset->company->id, diff --git a/app/Http/Transformers/ComponentsTransformer.php b/app/Http/Transformers/ComponentsTransformer.php index 97677af283..e758a95e3c 100644 --- a/app/Http/Transformers/ComponentsTransformer.php +++ b/app/Http/Transformers/ComponentsTransformer.php @@ -46,7 +46,7 @@ class ComponentsTransformer 'id' => (int) $component->company->id, 'name' => e($component->company->name), ] : null, - 'notes' => ($component->notes) ? e($component->notes) : null, + 'notes' => ($component->notes) ? Helper::parseEscapedMarkedown($component->notes) : null, 'created_at' => Helper::getFormattedDateObject($component->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($component->updated_at, 'datetime'), 'user_can_checkout' => ($component->numRemaining() > 0) ? 1 : 0, diff --git a/app/Http/Transformers/ConsumablesTransformer.php b/app/Http/Transformers/ConsumablesTransformer.php index b92f843b7f..27e70fcf0b 100644 --- a/app/Http/Transformers/ConsumablesTransformer.php +++ b/app/Http/Transformers/ConsumablesTransformer.php @@ -39,7 +39,7 @@ class ConsumablesTransformer 'purchase_cost' => Helper::formatCurrencyOutput($consumable->purchase_cost), 'purchase_date' => Helper::getFormattedDateObject($consumable->purchase_date, 'date'), 'qty' => (int) $consumable->qty, - 'notes' => ($consumable->notes) ? e($consumable->notes) : null, + 'notes' => ($consumable->notes) ? Helper::parseEscapedMarkedown($consumable->notes) : null, 'created_at' => Helper::getFormattedDateObject($consumable->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($consumable->updated_at, 'datetime'), ]; diff --git a/app/Http/Transformers/LicensesTransformer.php b/app/Http/Transformers/LicensesTransformer.php index 8df6b89f19..b5b0d841f5 100644 --- a/app/Http/Transformers/LicensesTransformer.php +++ b/app/Http/Transformers/LicensesTransformer.php @@ -34,7 +34,7 @@ class LicensesTransformer 'depreciation' => ($license->depreciation) ? ['id' => (int) $license->depreciation->id,'name'=> e($license->depreciation->name)] : null, 'purchase_cost' => Helper::formatCurrencyOutput($license->purchase_cost), 'purchase_cost_numeric' => $license->purchase_cost, - 'notes' => e($license->notes), + 'notes' => Helper::parseEscapedMarkedown($license->notes), 'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'), 'seats' => (int) $license->seats, 'free_seats_count' => (int) $license->free_seats_count, diff --git a/app/Http/Transformers/SuppliersTransformer.php b/app/Http/Transformers/SuppliersTransformer.php index e7546bfd15..e81198763d 100644 --- a/app/Http/Transformers/SuppliersTransformer.php +++ b/app/Http/Transformers/SuppliersTransformer.php @@ -43,7 +43,7 @@ class SuppliersTransformer 'licenses_count' => (int) $supplier->licenses_count, 'consumables_count' => (int) $supplier->consumables_count, 'components_count' => (int) $supplier->components_count, - 'notes' => ($supplier->notes) ? e($supplier->notes) : null, + 'notes' => ($supplier->notes) ? Helper::parseEscapedMarkedown($supplier->notes) : null, 'created_at' => Helper::getFormattedDateObject($supplier->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($supplier->updated_at, 'datetime'), diff --git a/app/Http/Transformers/UsersTransformer.php b/app/Http/Transformers/UsersTransformer.php index 867a884619..5a45a00124 100644 --- a/app/Http/Transformers/UsersTransformer.php +++ b/app/Http/Transformers/UsersTransformer.php @@ -53,7 +53,7 @@ class UsersTransformer 'id' => (int) $user->userloc->id, 'name'=> e($user->userloc->name), ] : null, - 'notes'=> e($user->notes), + 'notes'=> Helper::parseEscapedMarkedown($user->notes), 'permissions' => $user->decodePermissions(), 'activated' => ($user->activated == '1') ? true : false, 'autoassign_licenses' => ($user->autoassign_licenses == '1') ? true : false, From 85e717bc4e920bc5e3a7110d5d58193cb18d06e6 Mon Sep 17 00:00:00 2001 From: Ivan Nieto Vivanco Date: Wed, 28 Jun 2023 10:38:44 -0600 Subject: [PATCH 40/56] Fix cancel button style and translate title --- resources/lang/en/general.php | 1 + resources/views/hardware/requested.blade.php | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 28f9fd82ba..e8affbf945 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -436,6 +436,7 @@ return [ 'errors_importing' => 'Some Errors occurred while importing: ', 'warning' => 'WARNING: :warning', 'success_redirecting' => '"Success... Redirecting.', + 'cancel_request' => 'Cancel this item request', 'setup_successful_migrations' => 'Your database tables have been created', 'setup_migration_output' => 'Migration output:', 'setup_migration_create_user' => 'Next: Create User', diff --git a/resources/views/hardware/requested.blade.php b/resources/views/hardware/requested.blade.php index 25502b42c3..61e3b87c3f 100644 --- a/resources/views/hardware/requested.blade.php +++ b/resources/views/hardware/requested.blade.php @@ -24,7 +24,7 @@ 'id' => 'bulkForm']) }}
    - {{ Form::close() }} + @if ($requestedItems->count() > 0)
    'POST', 'route' => ['account/request-item', $request->itemType(), $request->requestable->id, true, $request->requestingUser()->id], ]) }} - + {{ Form::close() }} - + @@ -143,7 +138,6 @@ - {{ Form::close() }} @stop From a4b8723dcb4ec0e538158548ec372951904e3220 Mon Sep 17 00:00:00 2001 From: Ivan Nieto Vivanco Date: Wed, 28 Jun 2023 11:38:51 -0600 Subject: [PATCH 42/56] Delete notes column map from assets importer --- app/Http/Livewire/Importer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Http/Livewire/Importer.php b/app/Http/Livewire/Importer.php index 94f48fbad2..6b5770cb6b 100644 --- a/app/Http/Livewire/Importer.php +++ b/app/Http/Livewire/Importer.php @@ -214,7 +214,6 @@ class Importer extends Component 'model_notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]), 'manufacturer' => trans('general.manufacturer'), 'order_number' => trans('general.order_number'), - 'notes' => trans('general.notes'), 'image' => trans('general.importer.image_filename'), /** * Checkout fields: From 4c3a306a6ee37d1f3ef49e787862c67b5585a71a Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 Jun 2023 13:35:41 +0100 Subject: [PATCH 43/56] More shuffling of scopes Signed-off-by: snipe --- app/Http/Controllers/Api/AssetsController.php | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index dc87dc999d..222f528e4a 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -125,6 +125,8 @@ class AssetsController extends Controller $assets->InModelList($non_deprecable_models->toArray()); } + + // These are used by the API to query against specific ID numbers. // They are also used by the individual searches on detail pages like // locations, etc. @@ -136,12 +138,11 @@ class AssetsController extends Controller } } - - // Make sure the offset and limit are actually integers and do not exceed system limits - $offset = ($request->input('offset') > $assets->count()) ? $assets->count() : abs($request->input('offset')); - $limit = app('api_limit_value'); - - $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; + if ((! is_null($filter)) && (count($filter)) > 0) { + $assets->ByFilter($filter); + } elseif ($request->filled('search')) { + $assets->TextSearch($request->input('search')); + } // This is used by the audit reporting routes if (Gate::allows('audit', Asset::class)) { @@ -156,7 +157,6 @@ class AssetsController extends Controller } - // This is used by the sidenav, mostly // We switched from using query scopes here because of a Laravel bug @@ -206,7 +206,7 @@ class AssetsController extends Controller break; case 'Deployed': // more sad, horrible workarounds for laravel bugs when doing full text searches - $assets->where('assets.assigned_to', '>', '0'); + $assets->whereNotNull('assets.assigned_to'); break; case 'byod': // This is kind of redundant, since we already check for byod=1 above, but this keeps the @@ -232,12 +232,6 @@ class AssetsController extends Controller } - if ((! is_null($filter)) && (count($filter)) > 0) { - $assets->ByFilter($filter); - } elseif ($request->filled('search')) { - $assets->TextSearch($request->input('search')); - } - // Leave these under the TextSearch scope, else the fuzziness will override the specific ID (status ID, etc) requested if ($request->filled('status_id')) { $assets->where('assets.status_id', '=', $request->input('status_id')); @@ -313,7 +307,8 @@ class AssetsController extends Controller // in the allowed_columns array) $column_sort = in_array($sort_override, $allowed_columns) ? $sort_override : 'assets.created_at'; - + $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; + switch ($sort_override) { case 'model': $assets->OrderModels($order); @@ -350,6 +345,10 @@ class AssetsController extends Controller } + // Make sure the offset and limit are actually integers and do not exceed system limits + $offset = ($request->input('offset') > $assets->count()) ? $assets->count() : abs($request->input('offset')); + $limit = app('api_limit_value'); + $total = $assets->count(); $assets = $assets->skip($offset)->take($limit)->get(); From bcefe73c9cdbe2390d8d1163ec6719d96fc24a17 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 Jun 2023 16:52:09 +0100 Subject: [PATCH 44/56] Use proper alias for table scope Signed-off-by: snipe --- app/Models/Asset.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index c716b77d1e..e3d17d5e35 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -1566,7 +1566,7 @@ class Asset extends Depreciable */ public function scopeOrderModelNumber($query, $order) { - return $query->leftJoin('models as model_number_sort', 'assets.model_id', '=', 'models.id')->orderBy('models.model_number', $order); + return $query->leftJoin('models as model_number_sort', 'assets.model_id', '=', 'model_number_sort.id')->orderBy('model_number_sort.model_number', $order); } From d4cddebba56a791c9bea6deff45e6db8f8942ad0 Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Thu, 29 Jun 2023 11:21:21 -0700 Subject: [PATCH 45/56] fixes custom fields labels being unreadable --- resources/assets/less/skins/skin-yellow-dark.less | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/assets/less/skins/skin-yellow-dark.less b/resources/assets/less/skins/skin-yellow-dark.less index 2718eb638b..ffa8a46076 100644 --- a/resources/assets/less/skins/skin-yellow-dark.less +++ b/resources/assets/less/skins/skin-yellow-dark.less @@ -78,7 +78,9 @@ a.actions { color:#fff !important; } - +a:visited.label-default, a:link.label-default{ + color:#444; +} /** The dropdown is white, so use a darker color */ From f83effbb858d9c6a76e9fb1b4b0c8613c1501de0 Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Thu, 29 Jun 2023 11:25:40 -0700 Subject: [PATCH 46/56] removed unnecessary css rule --- resources/assets/less/skins/skin-yellow-dark.less | 3 --- 1 file changed, 3 deletions(-) diff --git a/resources/assets/less/skins/skin-yellow-dark.less b/resources/assets/less/skins/skin-yellow-dark.less index ffa8a46076..c111cb122c 100644 --- a/resources/assets/less/skins/skin-yellow-dark.less +++ b/resources/assets/less/skins/skin-yellow-dark.less @@ -161,9 +161,6 @@ h2.task_menu{ background: linear-gradient(to bottom, var(--header) 0%,var(--header) 100%); border-color: var(--header); } -.label-default{ - background-color:var(--back-sub); -} a.btn.btn-default{ color:var(--nav-link); } From faf2a235fb8ca6c240642ab3e42c14741994e0fe Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 Jun 2023 20:31:13 +0100 Subject: [PATCH 47/56] Updated dev assets Signed-off-by: snipe --- public/css/dist/skins/skin-yellow-dark.css | Bin 11589 -> 11598 bytes .../css/dist/skins/skin-yellow-dark.min.css | Bin 11589 -> 11598 bytes public/mix-manifest.json | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/css/dist/skins/skin-yellow-dark.css b/public/css/dist/skins/skin-yellow-dark.css index 1f16540750454e52e1a286cafc47bd74891d9b0b..09babaa6ab6a33aace2741dd4438637177e291fc 100644 GIT binary patch delta 79 zcmX>abuMbdFCN=OtFp}E%#zd;y`03P)EwQE)U?FXoDvXbu?v~c6ycQw0H*Z{00000 diff --git a/public/css/dist/skins/skin-yellow-dark.min.css b/public/css/dist/skins/skin-yellow-dark.min.css index 1f16540750454e52e1a286cafc47bd74891d9b0b..09babaa6ab6a33aace2741dd4438637177e291fc 100644 GIT binary patch delta 79 zcmX>abuMbdFCN=OtFp}E%#zd;y`03P)EwQE)U?FXoDvXbu?v~c6ycQw0H*Z{00000 diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 444f5cecbf..5255d8aa5c 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -7,7 +7,7 @@ "/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=6f0563e726c2fe4fab4026daaa5bfdf2", "/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=e6e53eef152bba01a4c666a4d8b01117", "/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=07273f6ca3c698a39e8fc2075af4fa07", - "/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=7c4badf178b44a4489dac90c0f772908", + "/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=c1f33574ecb9d3e69d9b8fe5bd68e101", "/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=7b315b9612b8fde8f9c5b0ddb6bba690", "/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=7d92dea45d94be7e1d4e427c728d335d", "/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=6fe68325d5356197672c27bc77cedcb4", @@ -40,7 +40,7 @@ "/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=f677207c6cf9678eb539abecb408c374", "/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=07273f6ca3c698a39e8fc2075af4fa07", "/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=7b315b9612b8fde8f9c5b0ddb6bba690", - "/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=7c4badf178b44a4489dac90c0f772908", + "/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=c1f33574ecb9d3e69d9b8fe5bd68e101", "/css/dist/skins/skin-red.min.css": "/css/dist/skins/skin-red.min.css?id=44bf834f2110504a793dadec132a5898", "/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=8ca888bbc050d9680cbb65021382acba", "/css/dist/skins/skin-purple.min.css": "/css/dist/skins/skin-purple.min.css?id=6fe68325d5356197672c27bc77cedcb4", From fb9b3a54530f7bd3694253da29ea290dea6ae5dc Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 Jun 2023 20:32:20 +0100 Subject: [PATCH 48/56] Switched from a colon to a hyphen to handle windows filesystems Signed-off-by: snipe --- app/Http/Controllers/SettingsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index fbb7f4e4ce..87fc98c197 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -1136,7 +1136,7 @@ class SettingsController extends Controller public function postBackups() { if (! config('app.lock_passwords')) { - Artisan::call('snipeit:backup', ['--filename' => 'manual-backup-'.date('Y-m-d-H:i:s')]); + Artisan::call('snipeit:backup', ['--filename' => 'manual-backup-'.date('Y-m-d-H-i-s')]); $output = Artisan::output(); // Backup completed From 7937542dcbbfeb3b560e54e4d2ad60f909b8baca Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 29 Jun 2023 21:15:50 +0100 Subject: [PATCH 49/56] =?UTF-8?q?Redirect=20if=20the=20license=20can?= =?UTF-8?q?=E2=80=99t=20be=20found?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: snipe --- app/Http/Controllers/Licenses/LicenseCheckoutController.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Licenses/LicenseCheckoutController.php b/app/Http/Controllers/Licenses/LicenseCheckoutController.php index a710497692..3a0f806584 100644 --- a/app/Http/Controllers/Licenses/LicenseCheckoutController.php +++ b/app/Http/Controllers/Licenses/LicenseCheckoutController.php @@ -30,15 +30,17 @@ class LicenseCheckoutController extends Controller // Check that the license is valid if ($license = License::find($licenseId)) { + $this->authorize('checkout', $license); // If the license is valid, check that there is an available seat if ($license->avail_seats_count < 1) { return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license'); } + return view('licenses/checkout', compact('license')); } - $this->authorize('checkout', $license); + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); + - return view('licenses/checkout', compact('license')); } /** From df90e924b4ae4357d9d72a70d948b59d60143b6a Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Thu, 29 Jun 2023 13:18:17 -0700 Subject: [PATCH 50/56] prevent labels from overlapping --- resources/views/hardware/labels.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/hardware/labels.blade.php b/resources/views/hardware/labels.blade.php index b25b08a0a9..49a981eceb 100644 --- a/resources/views/hardware/labels.blade.php +++ b/resources/views/hardware/labels.blade.php @@ -52,7 +52,7 @@ $qr_size = ($settings->alt_barcode_enabled=='1') && ($settings->alt_barcode!='') } img.barcode { display:block; - margin-top:-7px; + margin-top:-14px; width: 100%; } div.label-logo { From 1f4d2f1e4a0452754d6408aea3bbef6e84bb10c7 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Wed, 5 Jul 2023 14:27:10 +0100 Subject: [PATCH 51/56] Properly return SCIM Exceptions --- app/Exceptions/Handler.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 3b1ffb9b31..e89bffcb90 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -75,7 +75,8 @@ class Handler extends ExceptionHandler // Handle SCIM exceptions if ($e instanceof SCIMException) { - return response()->json(Helper::formatStandardApiResponse('error', null, 'Invalid SCIM Request'), 400); + return $e->render($request); + //return response()->json(Helper::formatStandardApiResponse('error', null, 'Invalid SCIM Request'), 400); } // Handle standard requests that fail because Carbon cannot parse the date on validation (when a submitted date value is definitely not a date) From a6a89ddd6c89c52bd04931a6c0734e48b4160d67 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Wed, 5 Jul 2023 14:31:08 +0100 Subject: [PATCH 52/56] Also log(debug) the error - could be useful for troubleshooting --- app/Exceptions/Handler.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index e89bffcb90..3d4db93452 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -75,8 +75,12 @@ class Handler extends ExceptionHandler // Handle SCIM exceptions if ($e instanceof SCIMException) { - return $e->render($request); - //return response()->json(Helper::formatStandardApiResponse('error', null, 'Invalid SCIM Request'), 400); + try { + $e->report(); // logs as 'debug', so shouldn't get too noisy + } catch(\Exception $reportException) { + //do nothing + } + return $e->render($request); // ALL SCIMExceptions have the 'render()' method } // Handle standard requests that fail because Carbon cannot parse the date on validation (when a submitted date value is definitely not a date) From d890d923ff21356dae4c20e1746d69f18eff23ee Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 5 Jul 2023 14:40:54 +0100 Subject: [PATCH 53/56] Bumped version Signed-off-by: snipe --- config/version.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/version.php b/config/version.php index ba58e48dc2..ba0dd3bace 100644 --- a/config/version.php +++ b/config/version.php @@ -1,10 +1,10 @@ 'v6.1.1', - 'full_app_version' => 'v6.1.1 - build 10847-g2ac4449ea', - 'build_version' => '10847', + 'app_version' => 'v6.1.2', + 'full_app_version' => 'v6.1.2 - build 10938-g32747cafd', + 'build_version' => '10938', 'prerelease_version' => '', - 'hash_version' => 'g2ac4449ea', - 'full_hash' => 'v6.1.1-605-g2ac4449ea', + 'hash_version' => 'g32747cafd', + 'full_hash' => 'v6.1.2-89-g32747cafd', 'branch' => 'develop', ); \ No newline at end of file From c85a33be6a9d1cd66334f91bc378c07da69057d4 Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 5 Jul 2023 17:28:08 +0100 Subject: [PATCH 54/56] Change settings table `saml_idp_metadata` to MEDIUMTEXT Signed-off-by: snipe --- ..._table_increase_saml_idp_metadata_size.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 database/migrations/2023_07_05_092237_change_settings_table_increase_saml_idp_metadata_size.php diff --git a/database/migrations/2023_07_05_092237_change_settings_table_increase_saml_idp_metadata_size.php b/database/migrations/2023_07_05_092237_change_settings_table_increase_saml_idp_metadata_size.php new file mode 100644 index 0000000000..0e200e11b5 --- /dev/null +++ b/database/migrations/2023_07_05_092237_change_settings_table_increase_saml_idp_metadata_size.php @@ -0,0 +1,36 @@ +mediumText('saml_idp_metadata')->nullable()->default(null)->change(); + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->text('saml_idp_metadata')->nullable()->default(null)->change(); + }); + } +} From a9d175a3965724284faded1a3b1c7aecbaf450cd Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 5 Jul 2023 18:47:48 +0100 Subject: [PATCH 55/56] Check for max PHP version Signed-off-by: snipe --- upgrade.php | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/upgrade.php b/upgrade.php index 69ab2ffdab..a287e3d1de 100644 --- a/upgrade.php +++ b/upgrade.php @@ -1,7 +1,9 @@ =". $php_min_works. " - <".$php_max_wontwork.") \n"; echo "--------------------------------------------------------\n\n"; -if (version_compare(PHP_VERSION, $required_php_min, '<')) { - echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ERROR !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"; - echo "This version of PHP (".PHP_VERSION.") is not compatible with Snipe-IT.\n"; - echo "Snipe-IT requires PHP version ".$required_php_min." or greater. Please upgrade \n"; - echo "your version of PHP (web/php-fcgi and cli) and try running this script again.\n\n\n"; - exit; +if ((version_compare(phpversion(), $php_min_works, '>=')) && (version_compare(phpversion(), $php_max_wontwork, '<'))) { + + echo "√ Current PHP version: (" . phpversion() . ") is at least " . $php_min_works . " and less than ".$php_max_wontwork."! Continuing... \n"; + echo sprintf("FYI: The php.ini used by this PHP is: %s\n\n", get_cfg_var('cfg_file_path')); } else { - echo "Current PHP version: (" . PHP_VERSION . ") is at least ".$required_php_min." - continuing... \n"; - echo sprintf("FYI: The php.ini used by this PHP is: %s\n\n", get_cfg_var('cfg_file_path')); + echo "!!!!!!!!!!!!!!!!!!!!!!!!! PHP VERSION ERROR !!!!!!!!!!!!!!!!!!!!!!!!!\n"; + echo "This version of PHP (".phpversion().") is NOT compatible with Snipe-IT.\n"; + echo "Snipe-IT requires PHP versions between ".$php_min_works." and ".$php_max_wontwork.".\n"; + echo "Please install a compatible version of PHP and re-run this script again. \n"; + echo "!!!!!!!!!!!!!!!!!!!!!!!!! ABORTING THE UPGRADER !!!!!!!!!!!!!!!!!!!!!!\n"; + exit; } - echo "Checking Required PHP extensions... \n\n"; // Get the list of installed extensions From ef160b0e154b5a21767cd9830a1f1346903d55f4 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Thu, 6 Jul 2023 10:49:57 -0700 Subject: [PATCH 56/56] Add span tag so label is displayed properly --- resources/views/categories/edit.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/categories/edit.blade.php b/resources/views/categories/edit.blade.php index 1705fe2332..813e8463e9 100755 --- a/resources/views/categories/edit.blade.php +++ b/resources/views/categories/edit.blade.php @@ -43,7 +43,7 @@ @if ($snipeSettings->default_eula_text!='') @else
    @@ -143,6 +143,7 @@ + {{ Form::close() }} @stop From e2c2736a9cdd2f2836e6df14fc9a8d2123e58357 Mon Sep 17 00:00:00 2001 From: Ivan Nieto Vivanco Date: Wed, 28 Jun 2023 11:23:37 -0600 Subject: [PATCH 41/56] Delete (gulp) Form for bulk edit since is not used in this view --- resources/views/hardware/requested.blade.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/resources/views/hardware/requested.blade.php b/resources/views/hardware/requested.blade.php index 61e3b87c3f..da90b3bf28 100644 --- a/resources/views/hardware/requested.blade.php +++ b/resources/views/hardware/requested.blade.php @@ -17,11 +17,6 @@
    - {{ Form::open([ - 'method' => 'POST', - 'route' => ['hardware/bulkedit'], - 'class' => 'form-inline', - 'id' => 'bulkForm']) }}
    @@ -51,7 +46,7 @@
    {{ trans('admin/hardware/form.expected_checkin') }} {{ trans('admin/hardware/table.requesting_user') }} {{ trans('admin/hardware/table.requested_date') }}{{ trans('button.actions') }}{{ trans('button.actions') }}