From a05c33febfb49b6a845e762817dd20e16db71d0e Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 22 Oct 2024 15:43:19 +0100 Subject: [PATCH] Squashed commit of the following: commit 147fcfb8ebc4ceeea96d803d6a455abeba54f45a Merge: 58a3d09b5 fdcc17ca2 Author: snipe Date: Tue Oct 22 15:12:55 2024 +0100 Merge pull request #15676 from Toreg87/fixes/api_create_user_fmcs Fix user creation with FullMultipleCompanySupport enabled over API commit 58a3d09b5fd7ffa979bfb9553cacbb24ae452462 Merge: 30a06a594 867fa2f36 Author: snipe Date: Tue Oct 22 14:55:42 2024 +0100 Merge pull request #15703 from marcusmoore/bug/sc-27188 Linked accessory files in activity report commit 30a06a594289571097e2d30901546bc9a17b4bac Merge: 6c6af78e0 ce3086317 Author: snipe Date: Tue Oct 22 11:47:06 2024 +0100 Merge pull request #15693 from marcusmoore/chore/remove-parallel-testing Removed brianium/paratest commit 6c6af78e0840fc4f134e5bbb7965f21f4adcc0e1 Merge: 9b06bbb6c 3f79fd7ea Author: snipe Date: Tue Oct 22 11:46:04 2024 +0100 Merge pull request #15705 from marcusmoore/tests/icon-component-test Added test to ensure icon component does not end in newline commit 3f79fd7ea744bd18134785c37b87a2f4bcff0347 Author: Marcus Moore Date: Mon Oct 21 17:07:40 2024 -0700 Add test to ensure icon component does not end in newline commit 9b06bbb6c37fcea9b6202ad9fb2b4d952210dd01 Merge: 46ad1d072 d7f70146f Author: snipe Date: Mon Oct 21 22:38:26 2024 +0100 Merge pull request #15704 from marcusmoore/bug/remove-extra-icon Removed second icon in accessory file list commit ce30863177e499a29f395c9c88ce9c67bd669a74 Author: Marcus Moore Date: Mon Oct 21 13:57:04 2024 -0700 Remove brianium/paratest dependency commit d7f70146f4a886795ddb118cc2f71bbadded72dc Author: Marcus Moore Date: Mon Oct 21 13:48:25 2024 -0700 Remove extra icon in accessory file upload list commit 867fa2f36e02bdfe0ee74ae98b590fd013f6fc7a Author: Marcus Moore Date: Mon Oct 21 12:40:24 2024 -0700 Display file in activity report for accessories commit 0933a2d4ea6d5babd6ef3e0e2f8350c2e088648d Author: Marcus Moore Date: Thu Oct 17 18:01:48 2024 -0700 Remove --parallel flag commit 46ad1d072f5c45d20c1b078d2b3f84a3a0f36632 Merge: bcb4bd9eb 3cf746d7d Author: snipe Date: Thu Oct 17 15:29:47 2024 +0100 Merge pull request #15680 from uberbrady/bulk_checkout_to_bulk_actions Bulk checkout to bulk actions commit bcb4bd9eb4e419e8a125a7dccd3e79c39dc13e21 Merge: 250037540 f50ccbcc4 Author: snipe Date: Thu Oct 17 10:20:13 2024 +0100 Merge pull request #15683 from Toreg87/fixes/outdated_comment Fix outdated comment in CompanyableTrait commit f50ccbcc492db6c98cabf6dc6752dd99ab82bce7 Author: Tobias Regnery Date: Thu Oct 17 11:07:28 2024 +0200 Fix outdated comment in CompanyableTrait As of commit 5800e8d the user model uses CompanyableTrait so remove this clearly outdated comment commit 3cf746d7df83ef3e7cfa45c602fc182ebe8f11e3 Author: Brady Wetherington Date: Wed Oct 16 23:13:32 2024 +0100 Rework the bulk checkout to not change how all checkouts work commit 6b7af802af41c92a36e77605415869c9e72ec192 Author: Brady Wetherington Date: Thu Oct 10 13:28:23 2024 +0100 Add 'bulk checkout' as one of the bulk actions in the bulk actions toolbar commit fdcc17ca2c33d38a7af505c99d9547e014f5f783 Author: Tobias Regnery Date: Wed Oct 16 11:18:24 2024 +0200 Fix user creation with FullMultipleCompanySupport enabled over API It is currently possible as a non-superuser to create a new user or patch an existing user with arbitrary company over the API if FullMultipleCompanySupport is enabled. Altough a highly unlikely scenario as the user needs permission to create API keys and new users, it is a bug that should get fixed. Add a call to getIdForCurrentUser() to normalize the company_id if FullMultipleCompanySupport is enabled. Signed-off-by: snipe --- .github/workflows/tests-mysql.yml | 2 +- .github/workflows/tests-postgres.yml | 2 +- .github/workflows/tests-sqlite.yml | 2 +- app/Http/Controllers/Api/UsersController.php | 6 + .../Assets/BulkAssetsController.php | 23 ++- .../Transformers/ActionlogsTransformer.php | 4 +- app/Models/CompanyableTrait.php | 3 - composer.json | 1 - composer.lock | 156 +----------------- .../lang/en-US/admin/hardware/message.php | 5 + resources/views/accessories/view.blade.php | 1 - .../views/hardware/bulk-checkout.blade.php | 7 + .../partials/asset-bulk-actions.blade.php | 23 +-- .../BladeComponents/IconComponentTest.php | 20 +++ 14 files changed, 73 insertions(+), 182 deletions(-) create mode 100644 tests/Unit/BladeComponents/IconComponentTest.php diff --git a/.github/workflows/tests-mysql.yml b/.github/workflows/tests-mysql.yml index 737a86dca..310414cda 100644 --- a/.github/workflows/tests-mysql.yml +++ b/.github/workflows/tests-mysql.yml @@ -76,4 +76,4 @@ jobs: DB_DATABASE: snipeit DB_PORT: ${{ job.services.mysql.ports[3306] }} DB_USERNAME: root - run: php artisan test --parallel + run: php artisan test diff --git a/.github/workflows/tests-postgres.yml b/.github/workflows/tests-postgres.yml index 0c361511b..ae48277be 100644 --- a/.github/workflows/tests-postgres.yml +++ b/.github/workflows/tests-postgres.yml @@ -74,4 +74,4 @@ jobs: DB_PORT: ${{ job.services.postgresql.ports[5432] }} DB_USERNAME: snipeit DB_PASSWORD: password - run: php artisan test --parallel + run: php artisan test diff --git a/.github/workflows/tests-sqlite.yml b/.github/workflows/tests-sqlite.yml index 49c7c92d8..8bf011516 100644 --- a/.github/workflows/tests-sqlite.yml +++ b/.github/workflows/tests-sqlite.yml @@ -58,4 +58,4 @@ jobs: - name: Execute tests (Unit and Feature tests) via PHPUnit env: DB_CONNECTION: sqlite_testing - run: php artisan test --parallel + run: php artisan test diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 4714b29ea..a9c8c26f1 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -14,6 +14,7 @@ use App\Http\Transformers\UsersTransformer; use App\Models\Actionlog; use App\Models\Asset; use App\Models\Accessory; +use App\Models\Company; use App\Models\Consumable; use App\Models\License; use App\Models\User; @@ -371,6 +372,7 @@ class UsersController extends Controller $user = new User; $user->fill($request->all()); + $user->company_id = Company::getIdForCurrentUser($request->input('company_id')); $user->created_by = auth()->id(); if ($request->has('permissions')) { @@ -452,6 +454,10 @@ class UsersController extends Controller $user->fill($request->all()); + if ($request->filled('company_id')) { + $user->company_id = Company::getIdForCurrentUser($request->input('company_id')); + } + if ($user->id == $request->input('manager_id')) { return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot be your own manager')); } diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index 1ce08e65e..c27cfe3e0 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -52,6 +52,10 @@ class BulkAssetsController extends Controller } $asset_ids = $request->input('ids'); + if ($request->input('bulk_actions') === 'checkout') { + $request->session()->flashInput(['selected_assets' => $asset_ids]); + return redirect()->route('hardware.bulkcheckout.show'); + } // Figure out where we need to send the user after the update is complete, and store that in the session $bulk_back_url = request()->headers->get('referer'); @@ -571,31 +575,34 @@ class BulkAssetsController extends Controller } $errors = []; - DB::transaction(function () use ($target, $admin, $checkout_at, $expected_checkin, $errors, $asset_ids, $request) { + DB::transaction(function () use ($target, $admin, $checkout_at, $expected_checkin, &$errors, $asset_ids, $request) { //NOTE: $errors is passsed by reference! foreach ($asset_ids as $asset_id) { $asset = Asset::findOrFail($asset_id); $this->authorize('checkout', $asset); - $error = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null); + $checkout_success = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null); + //TODO - I think this logic is duplicated in the checkOut method? if ($target->location_id != '') { $asset->location_id = $target->location_id; - $asset->unsetEventDispatcher(); - $asset->save(); + // TODO - I don't know why this is being saved without events + $asset::withoutEvents(function () use ($asset) { + $asset->save(); + }); } - if ($error) { - array_merge_recursive($errors, $asset->getErrors()->toArray()); + if (!$checkout_success) { + $errors = array_merge_recursive($errors, $asset->getErrors()->toArray()); } } }); if (! $errors) { // Redirect to the new asset page - return redirect()->to('hardware')->with('success', trans('admin/hardware/message.checkout.success')); + return redirect()->to('hardware')->with('success', trans_choice('admin/hardware/message.multi-checkout.success', $asset_ids)); } // Redirect to the asset management page with error - return redirect()->route('hardware.bulkcheckout.show')->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($errors); + return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans_choice('admin/hardware/message.multi-checkout.error', $asset_ids))->withErrors($errors); } catch (ModelNotFoundException $e) { return redirect()->route('hardware.bulkcheckout.show')->with('error', $e->getErrors()); } diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php index 49eee4241..4e6341c8f 100644 --- a/app/Http/Transformers/ActionlogsTransformer.php +++ b/app/Http/Transformers/ActionlogsTransformer.php @@ -141,6 +141,8 @@ class ActionlogsTransformer if ($actionlog->item) { if ($actionlog->itemType() == 'asset') { $file_url = route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]); + } elseif ($actionlog->itemType() == 'accessory') { + $file_url = route('show.accessoryfile', ['accessoryId' => $actionlog->item->id, 'fileId' => $actionlog->id]); } elseif ($actionlog->itemType() == 'license') { $file_url = route('show.licensefile', ['licenseId' => $actionlog->item->id, 'fileId' => $actionlog->id]); } elseif ($actionlog->itemType() == 'user') { @@ -345,4 +347,4 @@ class ActionlogsTransformer -} \ No newline at end of file +} diff --git a/app/Models/CompanyableTrait.php b/app/Models/CompanyableTrait.php index df67f2be4..04a620d8e 100644 --- a/app/Models/CompanyableTrait.php +++ b/app/Models/CompanyableTrait.php @@ -8,9 +8,6 @@ trait CompanyableTrait * This trait is used to scope models to the current company. To use this scope on companyable models, * we use the "use Companyable;" statement at the top of the mode. * - * We CANNOT USE THIS ON USERS, as it causes an infinite loop and prevents users from logging in, since this scope will be - * applied to the currently logged in (or logging in) user in addition to the user model for viewing lists of users. - * * @see \App\Models\Company\Company::scopeCompanyables() * @return void */ diff --git a/composer.json b/composer.json index 6d8931257..d3637c3a4 100644 --- a/composer.json +++ b/composer.json @@ -74,7 +74,6 @@ "ext-exif": "*" }, "require-dev": { - "brianium/paratest": "^7.0", "fakerphp/faker": "^1.16", "larastan/larastan": "^2.9", "mockery/mockery": "^1.4", diff --git a/composer.lock b/composer.lock index 3f79921b2..0631fc275 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": "3819ab4ef72eb77fabe494c0e746b83b", + "content-hash": "5341bc5be02b3c33e28e46e06dd99f29", "packages": [ { "name": "alek13/slack", @@ -11790,101 +11790,6 @@ ], "time": "2024-04-13T18:00:56+00:00" }, - { - "name": "brianium/paratest", - "version": "v7.3.1", - "source": { - "type": "git", - "url": "https://github.com/paratestphp/paratest.git", - "reference": "551f46f52a93177d873f3be08a1649ae886b4a30" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/551f46f52a93177d873f3be08a1649ae886b4a30", - "reference": "551f46f52a93177d873f3be08a1649ae886b4a30", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-simplexml": "*", - "fidry/cpu-core-counter": "^0.5.1 || ^1.0.0", - "jean85/pretty-package-versions": "^2.0.5", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", - "phpunit/php-code-coverage": "^10.1.7", - "phpunit/php-file-iterator": "^4.1.0", - "phpunit/php-timer": "^6.0", - "phpunit/phpunit": "^10.4.2", - "sebastian/environment": "^6.0.1", - "symfony/console": "^6.3.4 || ^7.0.0", - "symfony/process": "^6.3.4 || ^7.0.0" - }, - "require-dev": { - "doctrine/coding-standard": "^12.0.0", - "ext-pcov": "*", - "ext-posix": "*", - "infection/infection": "^0.27.6", - "phpstan/phpstan": "^1.10.40", - "phpstan/phpstan-deprecation-rules": "^1.1.4", - "phpstan/phpstan-phpunit": "^1.3.15", - "phpstan/phpstan-strict-rules": "^1.5.2", - "squizlabs/php_codesniffer": "^3.7.2", - "symfony/filesystem": "^6.3.1 || ^7.0.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/v7.3.1" - }, - "funding": [ - { - "url": "https://github.com/sponsors/Slamdunk", - "type": "github" - }, - { - "url": "https://paypal.me/filippotessarotto", - "type": "paypal" - } - ], - "time": "2023-10-31T09:24:17+00:00" - }, { "name": "clue/ndjson-react", "version": "v1.3.0", @@ -12781,65 +12686,6 @@ }, "time": "2020-07-09T08:09:16+00:00" }, - { - "name": "jean85/pretty-package-versions", - "version": "2.0.6", - "source": { - "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/f9fdd29ad8e6d024f52678b570e5593759b550b4", - "reference": "f9fdd29ad8e6d024f52678b570e5593759b550b4", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.0.0", - "php": "^7.1|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^3.2", - "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^1.4", - "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.6" - }, - "time": "2024-03-08T09:58:59+00:00" - }, { "name": "justinrainbow/json-schema", "version": "5.3.0", diff --git a/resources/lang/en-US/admin/hardware/message.php b/resources/lang/en-US/admin/hardware/message.php index 041d32f56..27877e02f 100644 --- a/resources/lang/en-US/admin/hardware/message.php +++ b/resources/lang/en-US/admin/hardware/message.php @@ -79,6 +79,11 @@ return [ 'no_assets_selected' => 'You must select at least one asset from the list', ], + 'multi-checkout' => [ + 'error' => 'Asset was not checked out, please try again|Assets were not checked out, please try again', + 'success' => 'Asset checked out successfully.|Assets checked out successfully.', + ], + 'checkin' => [ 'error' => 'Asset was not checked in, please try again', 'success' => 'Asset checked in successfully.', diff --git a/resources/views/accessories/view.blade.php b/resources/views/accessories/view.blade.php index e3f98bf61..4dc8802e8 100644 --- a/resources/views/accessories/view.blade.php +++ b/resources/views/accessories/view.blade.php @@ -161,7 +161,6 @@ showfile_routename="show.accessoryfile" deletefile_routename="delete/accessoryfile" :object="$accessory" /> - diff --git a/resources/views/hardware/bulk-checkout.blade.php b/resources/views/hardware/bulk-checkout.blade.php index 405e5e47c..39e2cdf10 100644 --- a/resources/views/hardware/bulk-checkout.blade.php +++ b/resources/views/hardware/bulk-checkout.blade.php @@ -115,5 +115,12 @@ @section('moar_scripts') @include('partials/assets-assigned') + @stop diff --git a/resources/views/partials/asset-bulk-actions.blade.php b/resources/views/partials/asset-bulk-actions.blade.php index b597ad647..992fb52bb 100644 --- a/resources/views/partials/asset-bulk-actions.blade.php +++ b/resources/views/partials/asset-bulk-actions.blade.php @@ -16,17 +16,20 @@ diff --git a/tests/Unit/BladeComponents/IconComponentTest.php b/tests/Unit/BladeComponents/IconComponentTest.php new file mode 100644 index 000000000..b418b3838 --- /dev/null +++ b/tests/Unit/BladeComponents/IconComponentTest.php @@ -0,0 +1,20 @@ + 'checkout'])->render(); + + $this->assertFalse( + Str::endsWith($renderedTemplateString, PHP_EOL), + 'Newline found at end of icon component. Bootstrap tables will not render if there is a newline at the end of the file.' + ); + } +}