From e1fb446888eeaadae11dbac2f4f30791989ddd66 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Thu, 4 Apr 2024 14:20:03 -0500 Subject: [PATCH 01/71] this is a pretty good start, need to know about other PR --- app/Http/Requests/StoreAssetRequest.php | 4 +++ .../Traits/MayContainCustomFields.php | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 app/Http/Requests/Traits/MayContainCustomFields.php diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index 8e7559673..587116de4 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Http\Requests\Traits\MayContainCustomFields; use App\Models\Asset; use App\Models\Company; use Carbon\Carbon; @@ -10,6 +11,7 @@ use Illuminate\Support\Facades\Gate; class StoreAssetRequest extends ImageUploadRequest { + use MayContainCustomFields; /** * Determine if the user is authorized to make this request. * @@ -36,6 +38,8 @@ class StoreAssetRequest extends ImageUploadRequest 'company_id' => $idForCurrentUser, 'assigned_to' => $assigned_to ?? null, ]); + + //$this->after(); } /** diff --git a/app/Http/Requests/Traits/MayContainCustomFields.php b/app/Http/Requests/Traits/MayContainCustomFields.php new file mode 100644 index 000000000..8acdacb07 --- /dev/null +++ b/app/Http/Requests/Traits/MayContainCustomFields.php @@ -0,0 +1,30 @@ +after(function ($validator) { + $custom_fields = $this->collect()->keys()->filter(function ($attributes) { + return str_starts_with($attributes, '_snipeit_'); + }); + if (count($custom_fields) > 0) { + if ($this->method() == 'POST') { + dd($this->model_id); + } elseif ($this->method() == 'PUT' || $this->method() == 'PATCH') { + dd($this->asset()); + } + } + + }); + } +} + From 52340aca783bf0d216e507fd43b7c089805d12d8 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Thu, 4 Apr 2024 17:41:10 -0500 Subject: [PATCH 02/71] just about wrapped up --- .../Traits/MayContainCustomFields.php | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/app/Http/Requests/Traits/MayContainCustomFields.php b/app/Http/Requests/Traits/MayContainCustomFields.php index 8acdacb07..5a3299b36 100644 --- a/app/Http/Requests/Traits/MayContainCustomFields.php +++ b/app/Http/Requests/Traits/MayContainCustomFields.php @@ -2,25 +2,27 @@ namespace App\Http\Requests\Traits; +use App\Models\AssetModel; + trait MayContainCustomFields { - //public function after() - //{ - // dd($this); - // $request_data = $this; - //} - + // this gets called automatically on a form request public function withValidator($validator) { $validator->after(function ($validator) { - $custom_fields = $this->collect()->keys()->filter(function ($attributes) { + $request_fields = $this->collect()->keys()->filter(function ($attributes) { return str_starts_with($attributes, '_snipeit_'); }); - if (count($custom_fields) > 0) { + if (count($request_fields) > 0) { if ($this->method() == 'POST') { - dd($this->model_id); + $request_fields->diff(AssetModel::find($this->model_id)->fieldset->fields->pluck('db_column')) + ->each(function ($request_field_name) use ($request_fields, $validator) { + // i could probably add some more conditions here to determine whether or not the column exists but just not on this asset model + // and then return a more helpful error message + $validator->errors()->add($request_field_name, 'This field does not seem to exist (at least on this asset), please double check your custom field names.'); + }); } elseif ($this->method() == 'PUT' || $this->method() == 'PATCH') { - dd($this->asset()); + // need to know about other pr before I can go down this route } } From 997eddfed1bda9d6559b9d7604f0cde1ddc7a7aa Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Thu, 4 Apr 2024 18:23:03 -0500 Subject: [PATCH 03/71] cleanup + notes for monday --- app/Http/Requests/StoreAssetRequest.php | 2 -- app/Http/Requests/Traits/MayContainCustomFields.php | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index 587116de4..b00baf90f 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -38,8 +38,6 @@ class StoreAssetRequest extends ImageUploadRequest 'company_id' => $idForCurrentUser, 'assigned_to' => $assigned_to ?? null, ]); - - //$this->after(); } /** diff --git a/app/Http/Requests/Traits/MayContainCustomFields.php b/app/Http/Requests/Traits/MayContainCustomFields.php index 5a3299b36..a506412fe 100644 --- a/app/Http/Requests/Traits/MayContainCustomFields.php +++ b/app/Http/Requests/Traits/MayContainCustomFields.php @@ -15,6 +15,7 @@ trait MayContainCustomFields }); if (count($request_fields) > 0) { if ($this->method() == 'POST') { + // refactor to eager load the fields??? $request_fields->diff(AssetModel::find($this->model_id)->fieldset->fields->pluck('db_column')) ->each(function ($request_field_name) use ($request_fields, $validator) { // i could probably add some more conditions here to determine whether or not the column exists but just not on this asset model @@ -23,9 +24,11 @@ trait MayContainCustomFields }); } elseif ($this->method() == 'PUT' || $this->method() == 'PATCH') { // need to know about other pr before I can go down this route + // it should be more or less the same, just have to get the asset model differently + // ($this->asset should work if the other PR is accepted) + return; } } - }); } } From f30439a54408e3564b3f23f229950a697478abf4 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Sun, 7 Apr 2024 17:07:46 -0500 Subject: [PATCH 04/71] small refactor, pretty much good to go now though --- .../Traits/MayContainCustomFields.php | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/app/Http/Requests/Traits/MayContainCustomFields.php b/app/Http/Requests/Traits/MayContainCustomFields.php index a506412fe..206217221 100644 --- a/app/Http/Requests/Traits/MayContainCustomFields.php +++ b/app/Http/Requests/Traits/MayContainCustomFields.php @@ -3,31 +3,36 @@ namespace App\Http\Requests\Traits; use App\Models\AssetModel; +use App\Models\CustomField; trait MayContainCustomFields { // this gets called automatically on a form request public function withValidator($validator) { - $validator->after(function ($validator) { + // find the model + if ($this->method() == 'POST') { + $asset_model = AssetModel::find($this->model_id); + } + if ($this->method() == 'PATCH' || $this->method() == 'PUT') { + // this is dependent on the asset update request PR + $asset_model = $this->asset; + } + // collect the custom fields in the request + $validator->after(function ($validator) use ($asset_model) { $request_fields = $this->collect()->keys()->filter(function ($attributes) { return str_starts_with($attributes, '_snipeit_'); }); + // if there are custom fields, find the one's that don't exist on the model's fieldset and add an error to the validator's error bag if (count($request_fields) > 0) { - if ($this->method() == 'POST') { - // refactor to eager load the fields??? - $request_fields->diff(AssetModel::find($this->model_id)->fieldset->fields->pluck('db_column')) + $request_fields->diff($asset_model->fieldset->fields->pluck('db_column')) ->each(function ($request_field_name) use ($request_fields, $validator) { - // i could probably add some more conditions here to determine whether or not the column exists but just not on this asset model - // and then return a more helpful error message - $validator->errors()->add($request_field_name, 'This field does not seem to exist (at least on this asset), please double check your custom field names.'); + if (CustomField::where('db_column', $request_field_name)->exists()) { + $validator->errors()->add($request_field_name, 'This field seems to exist, but is not available on this Asset Model\'s fieldset.'); + } else { + $validator->errors()->add($request_field_name, 'This field does not seem to exist, please double check your custom field names.'); + } }); - } elseif ($this->method() == 'PUT' || $this->method() == 'PATCH') { - // need to know about other pr before I can go down this route - // it should be more or less the same, just have to get the asset model differently - // ($this->asset should work if the other PR is accepted) - return; - } } }); } From 99d7155729b4dc9d1412b9e7f459d4b6086e6dfa Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Sun, 7 Apr 2024 19:50:53 -0500 Subject: [PATCH 05/71] translation strings --- app/Http/Requests/Traits/MayContainCustomFields.php | 4 ++-- resources/lang/en-US/validation.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/Http/Requests/Traits/MayContainCustomFields.php b/app/Http/Requests/Traits/MayContainCustomFields.php index 206217221..50b239b60 100644 --- a/app/Http/Requests/Traits/MayContainCustomFields.php +++ b/app/Http/Requests/Traits/MayContainCustomFields.php @@ -28,9 +28,9 @@ trait MayContainCustomFields $request_fields->diff($asset_model->fieldset->fields->pluck('db_column')) ->each(function ($request_field_name) use ($request_fields, $validator) { if (CustomField::where('db_column', $request_field_name)->exists()) { - $validator->errors()->add($request_field_name, 'This field seems to exist, but is not available on this Asset Model\'s fieldset.'); + $validator->errors()->add($request_field_name, trans('validation.custom.custom_field_not_found_on_model')); } else { - $validator->errors()->add($request_field_name, 'This field does not seem to exist, please double check your custom field names.'); + $validator->errors()->add($request_field_name, trans('validation.custom.custom_field_not_found')); } }); } diff --git a/resources/lang/en-US/validation.php b/resources/lang/en-US/validation.php index 05374e23a..630816354 100644 --- a/resources/lang/en-US/validation.php +++ b/resources/lang/en-US/validation.php @@ -126,6 +126,8 @@ return [ 'hashed_pass' => 'Your current password is incorrect', 'dumbpwd' => 'That password is too common.', 'statuslabel_type' => 'You must select a valid status label type', + 'custom_field_not_found' => 'This field does not seem to exist, please double check your custom field names.', + 'custom_field_not_found_on_model' => 'This field seems to exist, but is not available on this Asset Model\'s fieldset.', // date_format validation with slightly less stupid messages. It duplicates a lot, but it gets the job done :( // We use this because the default error message for date_format is reflects php Y-m-d, which non-PHP @@ -137,7 +139,6 @@ return [ 'expected_checkin.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format', 'start_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format', 'end_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format', - ], /* From 750015684d04cc3422df30018dd3c65e30a81f66 Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Tue, 23 Jul 2024 10:42:50 -0700 Subject: [PATCH 06/71] purges user storage files --- app/Console/Commands/Purge.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/Console/Commands/Purge.php b/app/Console/Commands/Purge.php index 7abd83c85..8922519c2 100644 --- a/app/Console/Commands/Purge.php +++ b/app/Console/Commands/Purge.php @@ -3,6 +3,7 @@ namespace App\Console\Commands; use App\Models\Accessory; +use App\Models\Actionlog; use App\Models\Asset; use App\Models\AssetModel; use App\Models\Category; @@ -15,6 +16,7 @@ use App\Models\Statuslabel; use App\Models\Supplier; use App\Models\User; use Illuminate\Console\Command; +use Illuminate\Support\Facades\Storage; class Purge extends Command { @@ -141,6 +143,15 @@ class Purge extends Command $this->info($users->count().' users purged.'); $user_assoc = 0; foreach ($users as $user) { + $rel_path = 'private_uploads/users'; + $filenames = Actionlog::where('action_type', 'uploaded') + ->where('item_id', $user->id) + ->pluck('filename'); + foreach($filenames as $filename) { + if (Storage::exists($rel_path.'/'.$filename)) { + Storage::delete($rel_path . '/' . $filename); + } + } $this->info('- User "'.$user->username.'" deleted.'); $user_assoc += $user->userlog()->count(); $user->userlog()->forceDelete(); From 869c06f454a06243abd8b9f33f7482ebe07288dd Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 23 Jul 2024 15:41:58 -0700 Subject: [PATCH 07/71] Register anonymous blade component namespace --- app/Providers/BladeServiceProvider.php | 25 +++++++++++++++++++++++++ config/app.php | 1 + resources/views/blade/example.blade.php | 3 +++ 3 files changed, 29 insertions(+) create mode 100644 app/Providers/BladeServiceProvider.php create mode 100644 resources/views/blade/example.blade.php diff --git a/app/Providers/BladeServiceProvider.php b/app/Providers/BladeServiceProvider.php new file mode 100644 index 000000000..024ee9d3d --- /dev/null +++ b/app/Providers/BladeServiceProvider.php @@ -0,0 +1,25 @@ + + Hi. +

From 5b8529bc83b6e8b6fef7c014bd059715dbb7b52d Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 24 Jul 2024 19:16:08 +0100 Subject: [PATCH 08/71] Fixed pluralization Signed-off-by: snipe --- resources/lang/si-LK/general.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/si-LK/general.php b/resources/lang/si-LK/general.php index 4c0d64fd9..0063808f9 100644 --- a/resources/lang/si-LK/general.php +++ b/resources/lang/si-LK/general.php @@ -556,7 +556,7 @@ return [ 'something_went_wrong' => 'Something went wrong with your request.', 'close' => 'Close', 'expires' => 'Expires', - 'map_fields'=> 'Map :item_type Field', + 'map_fields'=> 'Map :item_type Fields', 'remaining_var' => ':count Remaining', ]; From 63f0b5279d950092d9aa8f451dcb032809132828 Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 24 Jul 2024 20:13:01 +0100 Subject: [PATCH 09/71] Added check for purchase_date Signed-off-by: snipe --- app/Models/License.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/License.php b/app/Models/License.php index d8bc3f03b..2680424a8 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -50,7 +50,7 @@ class License extends Depreciable 'category_id' => 'required|exists:categories,id', 'company_id' => 'integer|nullable', 'purchase_cost'=> 'numeric|nullable|gte:0', - 'purchase_date' => 'date_format:Y-m-d|nullable|max:10', + 'purchase_date' => 'date_format:Y-m-d|nullable|max:10|required_with:depreciation_id', 'expiration_date' => 'date_format:Y-m-d|nullable|max:10', 'termination_date' => 'date_format:Y-m-d|nullable|max:10', 'min_amt' => 'numeric|nullable|gte:0', From adf58a06da86bca9a1320be636b199ae0fa20a32 Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 24 Jul 2024 20:13:11 +0100 Subject: [PATCH 10/71] Added check for purchase date Signed-off-by: snipe --- app/Models/Depreciable.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/app/Models/Depreciable.php b/app/Models/Depreciable.php index 721135873..6139cda08 100644 --- a/app/Models/Depreciable.php +++ b/app/Models/Depreciable.php @@ -158,17 +158,20 @@ class Depreciable extends SnipeModel public function time_until_depreciated() { - // @link http://www.php.net/manual/en/class.datetime.php - $d1 = new \DateTime(); - $d2 = $this->depreciated_date(); + if ($this->depreciated_date()) { + // @link http://www.php.net/manual/en/class.datetime.php + $d1 = new \DateTime(); + $d2 = $this->depreciated_date(); - // @link http://www.php.net/manual/en/class.dateinterval.php - $interval = $d1->diff($d2); - if (! $interval->invert) { - return $interval; - } else { - return new \DateInterval('PT0S'); //null interval (zero seconds from now) + // @link http://www.php.net/manual/en/class.dateinterval.php + $interval = $d1->diff($d2); + if (! $interval->invert) { + return $interval; + } else { + return new \DateInterval('PT0S'); //null interval (zero seconds from now) + } } + return false; } public function depreciated_date() From ef145e47b45d9601e23d5c317bdb28f555b71ef9 Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 24 Jul 2024 20:13:15 +0100 Subject: [PATCH 11/71] Added tests Signed-off-by: snipe --- .../Feature/Licenses/Ui/CreateLicenseTest.php | 42 +++++++++++++++++++ tests/Feature/Licenses/Ui/LicenseViewTest.php | 41 ++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 tests/Feature/Licenses/Ui/CreateLicenseTest.php create mode 100644 tests/Feature/Licenses/Ui/LicenseViewTest.php diff --git a/tests/Feature/Licenses/Ui/CreateLicenseTest.php b/tests/Feature/Licenses/Ui/CreateLicenseTest.php new file mode 100644 index 000000000..f24c3bd2c --- /dev/null +++ b/tests/Feature/Licenses/Ui/CreateLicenseTest.php @@ -0,0 +1,42 @@ +create(); + $this->actingAs(User::factory()->create()) + ->get(route('licenses.create', $license)) + ->assertForbidden(); + } + + + + public function testLicenseWithoutPurchaseDateFailsValidation() + { + $response = $this->actingAs(User::factory()->superuser()->create()) + ->from(route('licenses.create')) + ->post(route('licenses.store'), [ + 'name' => 'Test Invalid License', + 'seats' => '10', + 'category_id' => Category::factory()->forLicenses()->create()->id, + 'depreciation_id' => Depreciation::factory()->create()->id + ]); + $response->assertStatus(302); + $response->assertRedirect(route('licenses.create')); + $response->assertInvalid(['purchase_date']); + $response->assertSessionHasErrors(['purchase_date']); + $this->followRedirects($response)->assertSee(trans('general.error')); + $this->assertFalse(AssetModel::where('name', 'Test Invalid License')->exists()); + + } +} diff --git a/tests/Feature/Licenses/Ui/LicenseViewTest.php b/tests/Feature/Licenses/Ui/LicenseViewTest.php new file mode 100644 index 000000000..295b23c5f --- /dev/null +++ b/tests/Feature/Licenses/Ui/LicenseViewTest.php @@ -0,0 +1,41 @@ +create(); + $this->actingAs(User::factory()->create()) + ->get(route('licenses.show', $license)) + ->assertForbidden(); + } + + + public function testLicenseWithNoPurchaseDateDoesNotTriggerDepreciation() + { + $depreciation = Depreciation::factory()->create(['months' => 12]); + $license = License::factory()->create(['depreciation_id' => $depreciation->id, 'purchase_date' => null]); + $this->actingAs(User::factory()->superuser()->create()) + ->get(route('licenses.show', $license)) + ->assertOk(); + } + + public function testLicenseWithPurchaseDateDepreciatesCorrectly() + { + $depreciation = Depreciation::factory()->create(['months' => 12]); + $license = License::factory()->create(['depreciation_id' => $depreciation->id, 'purchase_date' => '2020-01-01']); + $this->actingAs(User::factory()->superuser()->create()) + ->get(route('licenses.show', $license)) + ->assertOk() + ->assertSee([ + '2021-01-01' + ], false); + } +} From da4ec145d764cdbcc4557e0af74f9ede8157312a Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 24 Jul 2024 20:17:30 +0100 Subject: [PATCH 12/71] Removed test no longer needed due to validation Signed-off-by: snipe --- tests/Feature/Licenses/Ui/LicenseViewTest.php | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/tests/Feature/Licenses/Ui/LicenseViewTest.php b/tests/Feature/Licenses/Ui/LicenseViewTest.php index 295b23c5f..3b1f7830d 100644 --- a/tests/Feature/Licenses/Ui/LicenseViewTest.php +++ b/tests/Feature/Licenses/Ui/LicenseViewTest.php @@ -16,17 +16,7 @@ class LicenseViewTest extends TestCase ->get(route('licenses.show', $license)) ->assertForbidden(); } - - - public function testLicenseWithNoPurchaseDateDoesNotTriggerDepreciation() - { - $depreciation = Depreciation::factory()->create(['months' => 12]); - $license = License::factory()->create(['depreciation_id' => $depreciation->id, 'purchase_date' => null]); - $this->actingAs(User::factory()->superuser()->create()) - ->get(route('licenses.show', $license)) - ->assertOk(); - } - + public function testLicenseWithPurchaseDateDepreciatesCorrectly() { $depreciation = Depreciation::factory()->create(['months' => 12]); From c3a2cdeee9684ca23ff6b25cd602b63b31b7646d Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 24 Jul 2024 20:53:58 +0100 Subject: [PATCH 13/71] Added assets endpoint for locations Signed-off-by: snipe --- .../Controllers/Api/LocationsController.php | 11 ++++++ routes/api.php | 2 +- .../Locations/Api/LocationsViewTest.php | 36 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/Locations/Api/LocationsViewTest.php diff --git a/app/Http/Controllers/Api/LocationsController.php b/app/Http/Controllers/Api/LocationsController.php index 2ceeb8374..73227e082 100644 --- a/app/Http/Controllers/Api/LocationsController.php +++ b/app/Http/Controllers/Api/LocationsController.php @@ -5,8 +5,10 @@ namespace App\Http\Controllers\Api; use App\Helpers\Helper; use App\Http\Requests\ImageUploadRequest; use App\Http\Controllers\Controller; +use App\Http\Transformers\AssetsTransformer; use App\Http\Transformers\LocationsTransformer; use App\Http\Transformers\SelectlistTransformer; +use App\Models\Asset; use App\Models\Location; use Illuminate\Http\Request; use Illuminate\Pagination\LengthAwarePaginator; @@ -222,6 +224,15 @@ class LocationsController extends Controller return response()->json(Helper::formatStandardApiResponse('error', null, $location->getErrors())); } + public function assets(Request $request, Location $location) : JsonResponse | array + { + $this->authorize('view', Asset::class); + $this->authorize('view', $location); + $assets = Asset::where('assigned_to', '=', $location->id)->where('assigned_type', '=', Location::class)->with('model', 'model.category', 'assetstatus', 'location', 'company', 'defaultLoc'); + $assets = $assets->get(); + return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request); + } + /** * Remove the specified resource from storage. * diff --git a/routes/api.php b/routes/api.php index b5311aa98..9fffd7566 100644 --- a/routes/api.php +++ b/routes/api.php @@ -712,7 +712,7 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'throttle:api']], functi Route::get('{location}/assets', [ Api\LocationsController::class, - 'getDataViewAssets' + 'assets' ] )->name('api.locations.viewassets'); diff --git a/tests/Feature/Locations/Api/LocationsViewTest.php b/tests/Feature/Locations/Api/LocationsViewTest.php new file mode 100644 index 000000000..b5bcff8e4 --- /dev/null +++ b/tests/Feature/Locations/Api/LocationsViewTest.php @@ -0,0 +1,36 @@ +create(); + $this->actingAsForApi(User::factory()->create()) + ->getJson(route('api.locations.show', $location->id)) + ->assertForbidden(); + } + + public function testViewingLocationAssetIndexRequiresPermission() + { + $location = Location::factory()->create(); + Asset::factory()->count(3)->assignedToLocation($location)->create(); + + $this->actingAsForApi(User::factory()->superuser()->create()) + ->getJson(route('api.locations.viewassets', $location->id)) + ->assertOk() + ->assertJsonStructure([ + 'total', + 'rows', + ]) + ->assertJson([ + 'total' => 3, + ]); + } +} From 590d13061a64b4e78a7e6b57468d56153a13833b Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 24 Jul 2024 20:57:26 +0100 Subject: [PATCH 14/71] One more test Signed-off-by: snipe --- tests/Feature/Locations/Api/LocationsViewTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/Feature/Locations/Api/LocationsViewTest.php b/tests/Feature/Locations/Api/LocationsViewTest.php index b5bcff8e4..1d57e5826 100644 --- a/tests/Feature/Locations/Api/LocationsViewTest.php +++ b/tests/Feature/Locations/Api/LocationsViewTest.php @@ -18,6 +18,14 @@ class LocationsViewTest extends TestCase } public function testViewingLocationAssetIndexRequiresPermission() + { + $location = Location::factory()->create(); + $this->actingAsForApi(User::factory()->create()) + ->getJson(route('api.locations.viewassets', $location->id)) + ->assertForbidden(); + } + + public function testViewingLocationAssetIndex() { $location = Location::factory()->create(); Asset::factory()->count(3)->assignedToLocation($location)->create(); From 9b422e5c974d80a76a35376a78d02b48b27c0978 Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 24 Jul 2024 21:42:20 +0100 Subject: [PATCH 15/71] Baremetrics BMPay breaks with CSP turned [sc-25011] Signed-off-by: snipe --- config/services.php | 6 ------ resources/views/layouts/default.blade.php | 3 --- resources/views/partials/bpay.blade.php | 15 --------------- 3 files changed, 24 deletions(-) delete mode 100644 resources/views/partials/bpay.blade.php diff --git a/config/services.php b/config/services.php index 21acb6778..07b1c1069 100644 --- a/config/services.php +++ b/config/services.php @@ -44,12 +44,6 @@ return [ 'secret' => env('STRIPE_SECRET'), ], - 'baremetrics' => [ - 'enabled' => env('ENABLE_BMPAY', false), - 'app_key' => env('BMPAY_PUBLIC_KEY', null), - 'stripe_id' => env('BMPAY_STRIPE_ID', null), - ], - 'google' => [ 'maps_api_key' => env('GOOGLE_MAPS_API'), ], diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index ee235d358..839d76905 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -1136,8 +1136,5 @@ dir="{{ Helper::determineLanguageDirection() }}"> @endif - @include('partials.bpay') - - diff --git a/resources/views/partials/bpay.blade.php b/resources/views/partials/bpay.blade.php deleted file mode 100644 index 0cf0be540..000000000 --- a/resources/views/partials/bpay.blade.php +++ /dev/null @@ -1,15 +0,0 @@ -@can('admin') - @if ((config('services.baremetrics.enabled')=='true') && (config('services.baremetrics.app_key')) && (config('services.baremetrics.stripe_id'))) - - @else - @endif -@endcan From a439d8abe8f241301b540e7f120b60041955153c Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 25 Jul 2024 16:08:46 +0100 Subject: [PATCH 16/71] Use fully qualified use statements Signed-off-by: snipe --- app/Models/CustomField.php | 2 +- app/Providers/ValidationServiceProvider.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Models/CustomField.php b/app/Models/CustomField.php index c1826a94d..dfa497136 100644 --- a/app/Models/CustomField.php +++ b/app/Models/CustomField.php @@ -7,7 +7,7 @@ use EasySlugger\Utf8Slugger; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Validation\Rule; -use Schema; +use Illuminate\Support\Facades\Schema; use Watson\Validating\ValidatingTrait; class CustomField extends Model { diff --git a/app/Providers/ValidationServiceProvider.php b/app/Providers/ValidationServiceProvider.php index 3d7f48978..041aaad98 100644 --- a/app/Providers/ValidationServiceProvider.php +++ b/app/Providers/ValidationServiceProvider.php @@ -10,7 +10,7 @@ use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Log; use Illuminate\Support\ServiceProvider; use Illuminate\Validation\Rule; -use Validator; +use Illuminate\Support\Facades\Validator; /** * This service provider handles a few custom validation rules. From 84df23e1f637722242a87b1f1a4857f3fa344871 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Thu, 25 Jul 2024 18:07:25 +0100 Subject: [PATCH 17/71] Better handle older SQL dumps that got created in Windows format --- app/Console/Commands/RestoreFromBackup.php | 27 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/app/Console/Commands/RestoreFromBackup.php b/app/Console/Commands/RestoreFromBackup.php index 1cc9b280e..b062bd173 100644 --- a/app/Console/Commands/RestoreFromBackup.php +++ b/app/Console/Commands/RestoreFromBackup.php @@ -30,8 +30,11 @@ class SQLStreamer { public function parse_sql(string $line): string { // take into account the 'start of line or not' setting as an instance variable? // 'continuation' lines for a permitted statement are PERMITTED. + // remove *only* line-feeds & carriage-returns; helpful for regexes against lines from + // Windows dumps + $line = trim($line, "\r\n"); if($this->statement_is_permitted && $line[0] === ' ') { - return $line; + return $line . "\n"; //re-add the newline } $table_regex = '`?([a-zA-Z0-9_]+)`?'; @@ -42,8 +45,12 @@ class SQLStreamer { "/^(INSERT INTO )$table_regex(.*)$/" => false, "/^UNLOCK TABLES/" => false, // "/^\\) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;/" => false, // FIXME not sure what to do here? - "/^\\)[a-zA-Z0-9_= ]*;$/" => false - // ^^^^^^ that bit should *exit* the 'perimitted' black + "/^\\)[a-zA-Z0-9_= ]*;$/" => false, + // ^^^^^^ that bit should *exit* the 'permitted' block + "/^\\(.*\\)[,;]$/" => false, //older MySQL dump style with one set of values per line + /* we *could* have made the ^INSERT INTO blah VALUES$ turn on the capturing state, and closed it with + a ^(blahblah);$ but it's cleaner to not have to manage the state machine. We're just going to + assume that (blahblah), or (blahblah); are values for INSERT and are always acceptable. */ ]; foreach($allowed_statements as $statement => $statechange) { @@ -67,7 +74,7 @@ class SQLStreamer { } //how do we *replace* the tablename? // print "RETURNING LINE: $line"; - return $line; + return $line . "\n"; //re-add newline } } // all that is not allowed is denied. @@ -164,7 +171,8 @@ class RestoreFromBackup extends Command {filename : The zip file to be migrated} {--no-progress : Don\'t show a progress bar} {--sanitize-guess-prefix : Guess and output the table-prefix needed to "sanitize" the SQL} - {--sanitize-with-prefix= : "Sanitize" the SQL, using the passed-in table prefix (can be learned from --sanitize-guess-prefix). Pass as just \'--sanitize-with-prefix=\' to use no prefix}'; + {--sanitize-with-prefix= : "Sanitize" the SQL, using the passed-in table prefix (can be learned from --sanitize-guess-prefix). Pass as just \'--sanitize-with-prefix=\' to use no prefix} + {--sql-stdout-only : ONLY "Sanitize" the SQL and print it to stdout - useful for debugging - probably requires --sanitize-with-prefix= }'; /** * The console command description. @@ -365,6 +373,15 @@ class RestoreFromBackup extends Command return $this->info("Re-run this command with '--sanitize-with-prefix=".$prefix."' to see an attempt to sanitze your SQL."); } + // If we're doing --sql-stdout-only, handle that now so we don't have to open pipes to mysql and all of that silliness + if ($this->option('sql-stdout-only')) { + $sql_importer = new SQLStreamer($sql_contents, STDOUT, $this->option('sanitize-with-prefix')); + $bytes_read = $sql_importer->line_aware_piping(); + return $this->warn("$bytes_read total bytes read"); + //TODO - it'd be nice to dump this message to STDERR so that STDOUT is just pure SQL, + // which would be good for redirecting to a file, and not having to trim the last line off of it + } + //how to invoke the restore? $pipes = []; From eb938bdba3f164b6d1f851636d1c2224c175ff53 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Thu, 25 Jul 2024 18:40:26 +0100 Subject: [PATCH 18/71] Create intermediate directories on restore if needed --- app/Console/Commands/RestoreFromBackup.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/Console/Commands/RestoreFromBackup.php b/app/Console/Commands/RestoreFromBackup.php index 1cc9b280e..9340b0363 100644 --- a/app/Console/Commands/RestoreFromBackup.php +++ b/app/Console/Commands/RestoreFromBackup.php @@ -466,6 +466,9 @@ class RestoreFromBackup extends Command $ugly_file_name = $za->statIndex($file_details['index'])['name']; $fp = $za->getStream($ugly_file_name); //$this->info("Weird problem, here are file details? ".print_r($file_details,true)); + if (!is_dir($file_details['dest'])) { + mkdir($file_details['dest'], 0755, true); //0755 is what Laravel uses, so we do that + } $migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w'); while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) { fwrite($migrated_file, $buffer); From 62655be2d041c3c56d9c1411e7b4d0ad44a04a2c Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 25 Jul 2024 18:41:37 +0100 Subject: [PATCH 19/71] Fixed BYOD label Signed-off-by: snipe --- resources/views/hardware/edit.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/hardware/edit.blade.php b/resources/views/hardware/edit.blade.php index d2d9cc8f0..2a125a1c3 100755 --- a/resources/views/hardware/edit.blade.php +++ b/resources/views/hardware/edit.blade.php @@ -135,7 +135,7 @@
-
- -
diff --git a/resources/views/layouts/edit-form.blade.php b/resources/views/layouts/edit-form.blade.php index 791590141..2a24db27f 100644 --- a/resources/views/layouts/edit-form.blade.php +++ b/resources/views/layouts/edit-form.blade.php @@ -66,7 +66,11 @@ {{ csrf_field() }} @yield('inputFields') - @include('partials.forms.edit.submit') +
diff --git a/resources/views/partials/forms/redirect_submit_options.blade.php b/resources/views/partials/forms/redirect_submit_options.blade.php deleted file mode 100644 index c960dbb86..000000000 --- a/resources/views/partials/forms/redirect_submit_options.blade.php +++ /dev/null @@ -1,36 +0,0 @@ - - - - \ No newline at end of file From 018b5684fc68ae5e7b549bcfb2bac9b5a39f9036 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 25 Jul 2024 22:02:03 +0100 Subject: [PATCH 22/71] Refactor helper method for redirection Signed-off-by: snipe --- app/Helpers/Helper.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index d97869d70..ef1de871f 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1494,7 +1494,7 @@ class Helper if ($redirect_option == 'index') { switch ($table) { case "Assets": - return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success')); + return route('hardware.index'); } } @@ -1502,7 +1502,7 @@ class Helper if ($redirect_option == 'item') { switch ($table) { case "Assets": - return redirect()->route('hardware.show', $id ? $id : $asset_id)->with('success', trans('admin/hardware/message.checkout.success')); + return route('hardware.show', $id ?? $asset_id); } } @@ -1510,11 +1510,12 @@ class Helper if ($redirect_option == 'target') { switch ($checkout_to_type) { case 'user': - return redirect()->route('users.show', $request->assigned_user)->with('success', trans('admin/hardware/message.checkout.success')); + \Log::error('We think the checkout type is user?'); + return route('users.show', $request->assigned_user); case 'location': - return redirect()->route('locations.show', $request->assigned_location)->with('success', trans('admin/hardware/message.checkout.success')); + return route('locations.show', $request->assigned_location); case 'asset': - return redirect()->route('hardware.show', $request->assigned_asset)->with('success', trans('admin/hardware/message.checkout.success')); + return route('hardware.show', $request->assigned_asset); } } return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error')); From 08f4fe5f35376183b412c85d807ac8f6c52aa3f5 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 25 Jul 2024 22:02:34 +0100 Subject: [PATCH 23/71] Add status messages to redirect Signed-off-by: snipe --- app/Http/Controllers/Assets/AssetCheckinController.php | 8 +++----- app/Http/Controllers/Assets/AssetCheckoutController.php | 5 +++-- app/Http/Controllers/Assets/AssetsController.php | 8 +++++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/Http/Controllers/Assets/AssetCheckinController.php b/app/Http/Controllers/Assets/AssetCheckinController.php index 4794fa041..f84a468a6 100644 --- a/app/Http/Controllers/Assets/AssetCheckinController.php +++ b/app/Http/Controllers/Assets/AssetCheckinController.php @@ -11,7 +11,6 @@ use App\Models\Asset; use App\Models\CheckoutAcceptance; use App\Models\LicenseSeat; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Log; use \Illuminate\Contracts\View\View; use \Illuminate\Http\RedirectResponse; @@ -83,7 +82,6 @@ class AssetCheckinController extends Controller } $asset->expected_checkin = null; - //$asset->last_checkout = null; $asset->last_checkin = now(); $asset->assignedTo()->disassociate($asset); $asset->accepted = null; @@ -128,12 +126,12 @@ class AssetCheckinController extends Controller $acceptance->delete(); }); - Session::put('redirect_option', $request->get('redirect_option')); - // Was the asset updated? + session()->put('redirect_option', $request->get('redirect_option')); + if ($asset->save()) { event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues)); - return Helper::getRedirectOption($asset, $assetId, 'Assets'); + return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))->with('success', trans('admin/hardware/message.checkin.success')); } // Redirect to the asset management page with error return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.error').$asset->getErrors()); diff --git a/app/Http/Controllers/Assets/AssetCheckoutController.php b/app/Http/Controllers/Assets/AssetCheckoutController.php index 355f9387b..05b766916 100644 --- a/app/Http/Controllers/Assets/AssetCheckoutController.php +++ b/app/Http/Controllers/Assets/AssetCheckoutController.php @@ -109,10 +109,11 @@ class AssetCheckoutController extends Controller } } - Session::put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); + session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) { - return Helper::getRedirectOption($request, $assetId, 'Assets'); + return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets')) + ->with('success', trans('admin/hardware/message.checkout.success')); } // Redirect to the asset management page with error return redirect()->to("hardware/$assetId/checkout")->with('error', trans('admin/hardware/message.checkout.error').$asset->getErrors()); diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index c418866b3..a55afdc14 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -207,8 +207,10 @@ class AssetsController extends Controller session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); + if ($success) { - return redirect()->route('hardware.index') + + return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets')) ->with('success-unescaped', trans('admin/hardware/message.create.success_linked', ['link' => route('hardware.show', ['hardware' => $asset->id]), 'id', 'tag' => e($asset->asset_tag)])); @@ -293,7 +295,6 @@ class AssetsController extends Controller public function update(ImageUploadRequest $request, $assetId = null) : RedirectResponse { - // Check if the asset exists if (! $asset = Asset::find($assetId)) { // Redirect to the asset management page with error @@ -395,7 +396,8 @@ class AssetsController extends Controller session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); if ($asset->save()) { - return Helper::getRedirectOption($request, $assetId, 'Assets'); + return redirect()->to(Helper::getRedirectOption($request, $assetId, 'Assets')) + ->with('success', trans('admin/hardware/message.update.success')); } return redirect()->back()->withInput()->withErrors($asset->getErrors()); From 068535a80c8fd9e9771422839d8bbbee11ea0211 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 25 Jul 2024 22:08:46 +0100 Subject: [PATCH 24/71] Removed logging Signed-off-by: snipe --- app/Helpers/Helper.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index ef1de871f..2d0fd4fb0 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1510,7 +1510,6 @@ class Helper if ($redirect_option == 'target') { switch ($checkout_to_type) { case 'user': - \Log::error('We think the checkout type is user?'); return route('users.show', $request->assigned_user); case 'location': return route('locations.show', $request->assigned_location); From 64082ada1e41a1b1908b484c76f36908d13d6da7 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 25 Jul 2024 22:08:51 +0100 Subject: [PATCH 25/71] Updated test Signed-off-by: snipe --- tests/Unit/Helpers/HelperTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Unit/Helpers/HelperTest.php b/tests/Unit/Helpers/HelperTest.php index 3ef114b79..993fe138d 100644 --- a/tests/Unit/Helpers/HelperTest.php +++ b/tests/Unit/Helpers/HelperTest.php @@ -35,7 +35,7 @@ class HelperTest extends TestCase 'request' =>(object) ['assigned_user' => 22], 'id' => 1, 'checkout_to_type' => 'user', - 'redirect_option' => 2, + 'redirect_option' => 'target', 'table' => 'Assets', 'route' => route('users.show', 22), ], @@ -43,7 +43,7 @@ class HelperTest extends TestCase 'request' =>(object) ['assigned_location' => 10], 'id' => 2, 'checkout_to_type' => 'location', - 'redirect_option' => 2, + 'redirect_option' => 'target', 'table' => 'Locations', 'route' => route('locations.show', 10), ], @@ -51,7 +51,7 @@ class HelperTest extends TestCase 'request' =>(object) ['assigned_asset' => 101], 'id' => 3, 'checkout_to_type' => 'asset', - 'redirect_option' => 2, + 'redirect_option' => 'target', 'table' => 'Assets', 'route' => route('hardware.show', 101), ], @@ -59,7 +59,7 @@ class HelperTest extends TestCase 'request' =>(object) ['assigned_asset' => null], 'id' => 999, 'checkout_to_type' => null, - 'redirect_option' => 1, + 'redirect_option' => 'item', 'table' => 'Assets', 'route' => route('hardware.show', 999), ], @@ -67,7 +67,7 @@ class HelperTest extends TestCase 'request' =>(object) ['assigned_asset' => null], 'id' => null, 'checkout_to_type' => null, - 'redirect_option' => 0, + 'redirect_option' => 'index', 'table' => 'Assets', 'route' => route('hardware.index'), ], @@ -78,7 +78,7 @@ class HelperTest extends TestCase Session::put('redirect_option', $data['redirect_option']); Session::put('checkout_to_type', $data['checkout_to_type']); - $redirect = Helper::getRedirectOption($data['request'],$data['id'], $data['table']); + $redirect = redirect()->to(Helper::getRedirectOption($data['request'],$data['id'], $data['table'])); $this->assertInstanceOf(RedirectResponse::class, $redirect); $this->assertEquals($data['route'], $redirect->getTargetUrl(), $scenario.'failed.'); From 57f6ecb1da5d3186e939858a009fb8b3389bb088 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 26 Jul 2024 10:24:13 +0100 Subject: [PATCH 26/71] Added created_by to license view Signed-off-by: snipe --- app/Http/Controllers/Api/LicensesController.php | 8 +++++++- app/Http/Transformers/LicensesTransformer.php | 4 ++++ app/Models/License.php | 13 +++++++++++++ app/Presenters/LicensePresenter.php | 7 +++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index 579d80eeb..71ad01b59 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -24,7 +24,7 @@ class LicensesController extends Controller { $this->authorize('view', License::class); - $licenses = License::with('company', 'manufacturer', 'supplier','category')->withCount('freeSeats as free_seats_count'); + $licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count'); if ($request->filled('company_id')) { $licenses->where('company_id', '=', $request->input('company_id')); @@ -70,6 +70,9 @@ class LicensesController extends Controller $licenses->where('depreciation_id', '=', $request->input('depreciation_id')); } + if ($request->filled('user_id')) { + $licenses->where('user_id', '=', $request->input('user_id')); + } if (($request->filled('maintained')) && ($request->input('maintained')=='true')) { $licenses->where('maintained','=',1); @@ -113,6 +116,9 @@ class LicensesController extends Controller case 'company': $licenses = $licenses->leftJoin('companies', 'licenses.company_id', '=', 'companies.id')->orderBy('companies.name', $order); break; + case 'created_by': + $licenses = $licenses->OrderCreatedBy($order); + break; default: $allowed_columns = [ diff --git a/app/Http/Transformers/LicensesTransformer.php b/app/Http/Transformers/LicensesTransformer.php index fa218da4d..4fad9b9a6 100644 --- a/app/Http/Transformers/LicensesTransformer.php +++ b/app/Http/Transformers/LicensesTransformer.php @@ -45,6 +45,10 @@ class LicensesTransformer 'maintained' => ($license->maintained == 1) ? true : false, 'supplier' => ($license->supplier) ? ['id' => (int) $license->supplier->id, 'name'=> e($license->supplier->name)] : null, 'category' => ($license->category) ? ['id' => (int) $license->category->id, 'name'=> e($license->category->name)] : null, + 'created_by' => ($license->adminuser) ? [ + 'id' => (int) $license->adminuser->id, + 'name'=> e($license->adminuser->present()->fullName()), + ] : null, 'created_at' => Helper::getFormattedDateObject($license->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($license->updated_at, 'datetime'), 'deleted_at' => Helper::getFormattedDateObject($license->deleted_at, 'datetime'), diff --git a/app/Models/License.php b/app/Models/License.php index 2680424a8..554929c0a 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -736,4 +736,17 @@ class License extends Depreciable return $query->leftJoin('companies as companies', 'licenses.company_id', '=', 'companies.id')->select('licenses.*') ->orderBy('companies.name', $order); } + + /** + * Query builder scope to order on the user that created it + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param text $order Order + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeOrderCreatedBy($query, $order) + { + return $query->leftJoin('users as users_sort', 'licenses.user_id', '=', 'users_sort.id')->select('licenses.*')->orderBy('users_sort.first_name', $order)->orderBy('users_sort.last_name', $order); + } } \ No newline at end of file diff --git a/app/Presenters/LicensePresenter.php b/app/Presenters/LicensePresenter.php index 8ca8e120f..1545cabd3 100644 --- a/app/Presenters/LicensePresenter.php +++ b/app/Presenters/LicensePresenter.php @@ -158,6 +158,13 @@ class LicensePresenter extends Presenter 'sortable' => true, 'visible' => false, 'title' => trans('general.order_number'), + ], [ + 'field' => 'created_by', + 'searchable' => false, + 'sortable' => true, + 'title' => trans('general.admin'), + 'visible' => false, + 'formatter' => 'usersLinkObjFormatter', ], [ 'field' => 'created_at', 'searchable' => false, From 243ab51def07b149002d98c9f0861ce70b418b24 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 26 Jul 2024 10:40:48 +0100 Subject: [PATCH 27/71] Fixed back button Signed-off-by: snipe --- resources/views/blade/redirect_submit_options.blade.php | 4 ++-- resources/views/hardware/checkin.blade.php | 2 +- resources/views/hardware/checkout.blade.php | 2 +- resources/views/hardware/edit.blade.php | 1 + resources/views/layouts/edit-form.blade.php | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/resources/views/blade/redirect_submit_options.blade.php b/resources/views/blade/redirect_submit_options.blade.php index 7771d25c4..f22d55d89 100644 --- a/resources/views/blade/redirect_submit_options.blade.php +++ b/resources/views/blade/redirect_submit_options.blade.php @@ -1,6 +1,6 @@ @props([ - 'route' => 'hardware.index', + 'index_route', 'button_label', 'disabled_select' => false, 'options' => [], @@ -10,7 +10,7 @@
diff --git a/resources/views/hardware/checkin.blade.php b/resources/views/hardware/checkin.blade.php index 691c04852..1efd39427 100755 --- a/resources/views/hardware/checkin.blade.php +++ b/resources/views/hardware/checkin.blade.php @@ -128,7 +128,7 @@
From b6d9f736e30049235b9be1d7f5e9cc1204ee1175 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 26 Jul 2024 10:41:28 +0100 Subject: [PATCH 28/71] Pulled use session Signed-off-by: snipe --- app/Http/Controllers/Assets/AssetsController.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index a55afdc14..8c02baf5d 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -23,7 +23,6 @@ use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Gate; use Illuminate\Http\Request; use Illuminate\Support\Facades\Crypt; -use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Validator; use League\Csv\Reader; From 759ab78f80b88b35db3027c6f2c1e7a01265e2df Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 26 Jul 2024 11:27:36 +0100 Subject: [PATCH 29/71] Added more redirects Signed-off-by: snipe --- app/Helpers/Helper.php | 24 ++++- .../Accessories/AccessoriesController.php | 8 +- .../Components/ComponentsController.php | 8 +- .../Consumables/ConsumablesController.php | 8 +- .../Licenses/LicensesController.php | 8 +- .../Controllers/Users/UsersController.php | 7 +- resources/views/accessories/edit.blade.php | 5 + resources/views/components/edit.blade.php | 5 + resources/views/consumables/edit.blade.php | 5 + resources/views/hardware/edit.blade.php | 2 +- resources/views/licenses/edit.blade.php | 5 + resources/views/users/edit.blade.php | 11 ++- tests/Unit/Helpers/HelperTest.php | 99 ++++++++++++++++++- 13 files changed, 173 insertions(+), 22 deletions(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 2d0fd4fb0..6166d6668 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1484,7 +1484,7 @@ class Helper } - static public function getRedirectOption($request, $id, $table, $asset_id = null) + static public function getRedirectOption($request, $id, $table, $item_id = null) { $redirect_option = Session::get('redirect_option'); @@ -1495,6 +1495,16 @@ class Helper switch ($table) { case "Assets": return route('hardware.index'); + case "Users": + return route('users.index'); + case "Licenses": + return route('licenses.index'); + case "Accessories": + return route('accessories.index'); + case "Components": + return route('components.index'); + case "Consumables": + return route('consumables.index'); } } @@ -1502,7 +1512,17 @@ class Helper if ($redirect_option == 'item') { switch ($table) { case "Assets": - return route('hardware.show', $id ?? $asset_id); + return route('hardware.show', $id ?? $item_id); + case "Users": + return route('users.show', $id ?? $item_id); + case "Licenses": + return route('licenses.show', $id ?? $item_id); + case "Accessories": + return route('accessories.show', $id ?? $item_id); + case "Components": + return route('components.show', $id ?? $item_id); + case "Consumables": + return route('consumables.show', $id ?? $item_id); } } diff --git a/app/Http/Controllers/Accessories/AccessoriesController.php b/app/Http/Controllers/Accessories/AccessoriesController.php index bb2e74899..722638ad8 100755 --- a/app/Http/Controllers/Accessories/AccessoriesController.php +++ b/app/Http/Controllers/Accessories/AccessoriesController.php @@ -79,10 +79,11 @@ class AccessoriesController extends Controller $accessory = $request->handleImages($accessory); + session()->put(['redirect_option' => $request->get('redirect_option')]); // Was the accessory created? if ($accessory->save()) { // Redirect to the new accessory page - return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.create.success')); + return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))->with('success', trans('admin/accessories/message.create.success')); } return redirect()->back()->withInput()->withErrors($accessory->getErrors()); @@ -176,9 +177,10 @@ class AccessoriesController extends Controller $accessory = $request->handleImages($accessory); - // Was the accessory updated? + session()->put(['redirect_option' => $request->get('redirect_option')]); + if ($accessory->save()) { - return redirect()->route('accessories.index')->with('success', trans('admin/accessories/message.update.success')); + return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))->with('success', trans('admin/accessories/message.update.success')); } } else { return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist')); diff --git a/app/Http/Controllers/Components/ComponentsController.php b/app/Http/Controllers/Components/ComponentsController.php index 33ebde645..57cd0a2b4 100644 --- a/app/Http/Controllers/Components/ComponentsController.php +++ b/app/Http/Controllers/Components/ComponentsController.php @@ -86,8 +86,10 @@ class ComponentsController extends Controller $component = $request->handleImages($component); + session()->put(['redirect_option' => $request->get('redirect_option')]); + if ($component->save()) { - return redirect()->route('components.index')->with('success', trans('admin/components/message.create.success')); + return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.create.success')); } return redirect()->back()->withInput()->withErrors($component->getErrors()); @@ -160,8 +162,10 @@ class ComponentsController extends Controller $component = $request->handleImages($component); + session()->put(['redirect_option' => $request->get('redirect_option')]); + if ($component->save()) { - return redirect()->route('components.index')->with('success', trans('admin/components/message.update.success')); + return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.update.success')); } return redirect()->back()->withInput()->withErrors($component->getErrors()); diff --git a/app/Http/Controllers/Consumables/ConsumablesController.php b/app/Http/Controllers/Consumables/ConsumablesController.php index 883d5849e..42c0766fe 100644 --- a/app/Http/Controllers/Consumables/ConsumablesController.php +++ b/app/Http/Controllers/Consumables/ConsumablesController.php @@ -87,8 +87,10 @@ class ConsumablesController extends Controller $consumable = $request->handleImages($consumable); + session()->put(['redirect_option' => $request->get('redirect_option')]); + if ($consumable->save()) { - return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.create.success')); + return redirect()->to(Helper::getRedirectOption($request, $consumable->id, 'Consumables'))->with('success', trans('admin/consumables/message.create.success')); } return redirect()->back()->withInput()->withErrors($consumable->getErrors()); @@ -160,8 +162,10 @@ class ConsumablesController extends Controller $consumable = $request->handleImages($consumable); + session()->put(['redirect_option' => $request->get('redirect_option')]); + if ($consumable->save()) { - return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.update.success')); + return redirect()->to(Helper::getRedirectOption($request, $consumable->id, 'Consumables'))->with('success', trans('admin/consumables/message.update.success')); } return redirect()->back()->withInput()->withErrors($consumable->getErrors()); diff --git a/app/Http/Controllers/Licenses/LicensesController.php b/app/Http/Controllers/Licenses/LicensesController.php index 01de4b4d4..7a51344dd 100755 --- a/app/Http/Controllers/Licenses/LicensesController.php +++ b/app/Http/Controllers/Licenses/LicensesController.php @@ -102,8 +102,10 @@ class LicensesController extends Controller $license->user_id = Auth::id(); $license->min_amt = $request->input('min_amt'); + session()->put(['redirect_option' => $request->get('redirect_option')]); + if ($license->save()) { - return redirect()->route('licenses.index')->with('success', trans('admin/licenses/message.create.success')); + return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.create.success')); } return redirect()->back()->withInput()->withErrors($license->getErrors()); @@ -180,8 +182,10 @@ class LicensesController extends Controller $license->category_id = $request->input('category_id'); $license->min_amt = $request->input('min_amt'); + session()->put(['redirect_option' => $request->get('redirect_option')]); + if ($license->save()) { - return redirect()->route('licenses.show', ['license' => $licenseId])->with('success', trans('admin/licenses/message.update.success')); + return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.update.success')); } // If we can't adjust the number of seats, the error is flashed to the session by the event handler in License.php return redirect()->back()->withInput()->withErrors($license->getErrors()); diff --git a/app/Http/Controllers/Users/UsersController.php b/app/Http/Controllers/Users/UsersController.php index 7cff29fe5..1e203e71d 100755 --- a/app/Http/Controllers/Users/UsersController.php +++ b/app/Http/Controllers/Users/UsersController.php @@ -133,6 +133,8 @@ class UsersController extends Controller // we have to invoke the app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar'); + session()->put(['redirect_option' => $request->get('redirect_option')]); + if ($user->save()) { if ($request->filled('groups')) { $user->groups()->sync($request->input('groups')); @@ -152,7 +154,7 @@ class UsersController extends Controller $user->notify(new WelcomeNotification($data)); } - return redirect()->route('users.index')->with('success', trans('admin/users/message.success.create')); + return redirect()->to(Helper::getRedirectOption($request, $user->id, 'Users'))->with('success', trans('admin/users/message.success.create')); } return redirect()->back()->withInput()->withErrors($user->getErrors()); @@ -309,10 +311,11 @@ class UsersController extends Controller // Handle uploaded avatar app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar'); + session()->put(['redirect_option' => $request->get('redirect_option')]); if ($user->save()) { // Redirect to the user page - return redirect()->route('users.index') + return redirect()->to(Helper::getRedirectOption($request, $user->id, 'Users')) ->with('success', trans('admin/users/message.success.update')); } diff --git a/resources/views/accessories/edit.blade.php b/resources/views/accessories/edit.blade.php index 068fddc26..8e0503400 100644 --- a/resources/views/accessories/edit.blade.php +++ b/resources/views/accessories/edit.blade.php @@ -4,6 +4,11 @@ 'helpPosition' => 'right', 'helpText' => trans('help.accessories'), 'formAction' => (isset($item->id)) ? route('accessories.update', ['accessory' => $item->id]) : route('accessories.store'), + 'index_route' => 'accessories.index', + 'options' => [ + 'index' => trans('admin/hardware/form.redirect_to_all', ['type' => 'accessories']), + 'item' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.accessory')]), + ] ]) {{-- Page content --}} diff --git a/resources/views/components/edit.blade.php b/resources/views/components/edit.blade.php index 5279f0399..ce77b5130 100644 --- a/resources/views/components/edit.blade.php +++ b/resources/views/components/edit.blade.php @@ -4,6 +4,11 @@ 'helpPosition' => 'right', 'helpText' => trans('help.components'), 'formAction' => (isset($item->id)) ? route('components.update', ['component' => $item->id]) : route('components.store'), + 'index_route' => 'components.index', + 'options' => [ + 'index' => trans('admin/hardware/form.redirect_to_all', ['type' => 'components']), + 'item' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.component')]), + ] ]) diff --git a/resources/views/consumables/edit.blade.php b/resources/views/consumables/edit.blade.php index f32e74b19..300a7114d 100644 --- a/resources/views/consumables/edit.blade.php +++ b/resources/views/consumables/edit.blade.php @@ -4,6 +4,11 @@ 'helpPosition' => 'right', 'helpText' => trans('help.consumables'), 'formAction' => (isset($item->id)) ? route('consumables.update', ['consumable' => $item->id]) : route('consumables.store'), + 'index_route' => 'consumables.index', + 'options' => [ + 'index' => trans('admin/hardware/form.redirect_to_all', ['type' => 'consumables']), + 'item' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.consumable')]), + ] ]) {{-- Page content --}} @section('inputFields') diff --git a/resources/views/hardware/edit.blade.php b/resources/views/hardware/edit.blade.php index 7a543e921..f31326cc4 100755 --- a/resources/views/hardware/edit.blade.php +++ b/resources/views/hardware/edit.blade.php @@ -3,10 +3,10 @@ 'createText' => trans('admin/hardware/form.create'), 'updateText' => trans('admin/hardware/form.update'), 'topSubmit' => true, - 'index_route' => 'hardware.index', 'helpText' => trans('help.assets'), 'helpPosition' => 'right', 'formAction' => ($item->id) ? route('hardware.update', ['hardware' => $item->id]) : route('hardware.store'), + 'index_route' => 'hardware.index', 'options' => [ 'index' => trans('admin/hardware/form.redirect_to_all', ['type' => 'assets']), 'item' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.asset')]), diff --git a/resources/views/licenses/edit.blade.php b/resources/views/licenses/edit.blade.php index 450e4357a..b8429a212 100755 --- a/resources/views/licenses/edit.blade.php +++ b/resources/views/licenses/edit.blade.php @@ -3,6 +3,11 @@ 'updateText' => trans('admin/licenses/form.update'), 'topSubmit' => true, 'formAction' => ($item->id) ? route('licenses.update', ['license' => $item->id]) : route('licenses.store'), + 'index_route' => 'licenses.index', + 'options' => [ + 'index' => trans('admin/hardware/form.redirect_to_all', ['type' => 'licenses']), + 'item' => trans('admin/hardware/form.redirect_to_type', ['type' => trans('general.license')]), + ] ]) {{-- Page content --}} diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index 814c2f28e..200acb552 100755 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -596,9 +596,14 @@
- + diff --git a/tests/Unit/Helpers/HelperTest.php b/tests/Unit/Helpers/HelperTest.php index 993fe138d..2fb1c58e2 100644 --- a/tests/Unit/Helpers/HelperTest.php +++ b/tests/Unit/Helpers/HelperTest.php @@ -31,7 +31,7 @@ class HelperTest extends TestCase public function testGetRedirectOptionMethod() { $test_data = [ - 'Option 2: redirect for user assigned to ' => [ + 'Option target: redirect for user assigned to ' => [ 'request' =>(object) ['assigned_user' => 22], 'id' => 1, 'checkout_to_type' => 'user', @@ -39,7 +39,7 @@ class HelperTest extends TestCase 'table' => 'Assets', 'route' => route('users.show', 22), ], - 'Option 2: redirect location assigned to ' => [ + 'Option target: redirect location assigned to ' => [ 'request' =>(object) ['assigned_location' => 10], 'id' => 2, 'checkout_to_type' => 'location', @@ -47,7 +47,7 @@ class HelperTest extends TestCase 'table' => 'Locations', 'route' => route('locations.show', 10), ], - 'Option 2: redirect back to asset assigned to ' => [ + 'Option target: redirect back to asset assigned to ' => [ 'request' =>(object) ['assigned_asset' => 101], 'id' => 3, 'checkout_to_type' => 'asset', @@ -55,7 +55,7 @@ class HelperTest extends TestCase 'table' => 'Assets', 'route' => route('hardware.show', 101), ], - 'Option 1: redirect back to asset ' => [ + 'Option item: redirect back to asset ' => [ 'request' =>(object) ['assigned_asset' => null], 'id' => 999, 'checkout_to_type' => null, @@ -63,7 +63,7 @@ class HelperTest extends TestCase 'table' => 'Assets', 'route' => route('hardware.show', 999), ], - 'Option 0: redirect back to index ' => [ + 'Option index: redirect back to asset index ' => [ 'request' =>(object) ['assigned_asset' => null], 'id' => null, 'checkout_to_type' => null, @@ -71,6 +71,95 @@ class HelperTest extends TestCase 'table' => 'Assets', 'route' => route('hardware.index'), ], + + 'Option item: redirect back to user ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => 999, + 'checkout_to_type' => null, + 'redirect_option' => 'item', + 'table' => 'Users', + 'route' => route('users.show', 999), + ], + + 'Option index: redirect back to user index ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => null, + 'checkout_to_type' => null, + 'redirect_option' => 'index', + 'table' => 'Users', + 'route' => route('users.index'), + ], + + 'Option item: redirect back to license ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => 999, + 'checkout_to_type' => null, + 'redirect_option' => 'item', + 'table' => 'Licenses', + 'route' => route('licenses.show', 999), + ], + + 'Option index: redirect back to license index ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => null, + 'checkout_to_type' => null, + 'redirect_option' => 'index', + 'table' => 'Licenses', + 'route' => route('licenses.index'), + ], + + 'Option item: redirect back to accessory list ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => 999, + 'checkout_to_type' => null, + 'redirect_option' => 'item', + 'table' => 'Accessories', + 'route' => route('accessories.show', 999), + ], + + 'Option index: redirect back to accessory index ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => null, + 'checkout_to_type' => null, + 'redirect_option' => 'index', + 'table' => 'Accessories', + 'route' => route('accessories.index'), + ], + 'Option item: redirect back to consumable ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => 999, + 'checkout_to_type' => null, + 'redirect_option' => 'item', + 'table' => 'Consumables', + 'route' => route('consumables.show', 999), + ], + + 'Option index: redirect back to consumables index ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => null, + 'checkout_to_type' => null, + 'redirect_option' => 'index', + 'table' => 'Consumables', + 'route' => route('consumables.index'), + ], + + 'Option item: redirect back to component ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => 999, + 'checkout_to_type' => null, + 'redirect_option' => 'item', + 'table' => 'Components', + 'route' => route('components.show', 999), + ], + + 'Option index: redirect back to component index ' => [ + 'request' =>(object) ['assigned_asset' => null], + 'id' => null, + 'checkout_to_type' => null, + 'redirect_option' => 'index', + 'table' => 'Components', + 'route' => route('components.index'), + ], ]; foreach ($test_data as $scenario => $data ) { From daf5a800810edda32d3ac56884de7611efbda262 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Fri, 26 Jul 2024 12:03:03 +0100 Subject: [PATCH 30/71] Use a similar loop for the minification step for CSS --- webpack.mix.js | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/webpack.mix.js b/webpack.mix.js index acbb312d4..fee66acfb 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -79,6 +79,21 @@ for (var i in skins) { ) } +var css_skins = fs.readdirSync("public/css/dist/skins"); +for (var i in css_skins) { + if (css_skins[i].endsWith(".min.css")) { + //don't minify already minified skinns + continue; + } + if (css_skins[i].endsWith(".css")) { + // only minify files ending with '.css' + mix.minify("public/css/dist/skins/" + css_skins[i]).version(); + } + //TODO - if we only ever use the minified versions, this could be simplified down to one line (above) + // but it stays like this so we have the minified and non-minified versions of the skins + // right now the code seems to use the un-minified skins +} + /** * Combine bootstrap table css */ @@ -149,27 +164,4 @@ mix ["./public/js/build/vendor.js", "./public/js/build/app.js"], "./public/js/dist/all.js" ) - .version(); - -/** - * Copy, minify and version skins - */ -mix - .minify([ - "./public/css/dist/skins/skin-green.css", - "./public/css/dist/skins/skin-green-dark.css", - "./public/css/dist/skins/skin-black.css", - "./public/css/dist/skins/skin-black-dark.css", - "./public/css/dist/skins/skin-blue.css", - "./public/css/dist/skins/skin-blue-dark.css", - "./public/css/dist/skins/skin-yellow.css", - "./public/css/dist/skins/skin-yellow-dark.css", - "./public/css/dist/skins/skin-red.css", - "./public/css/dist/skins/skin-red-dark.css", - "./public/css/dist/skins/skin-purple.css", - "./public/css/dist/skins/skin-purple-dark.css", - "./public/css/dist/skins/skin-orange.css", - "./public/css/dist/skins/skin-orange-dark.css", - "./public/css/dist/skins/skin-contrast.css", - ]) - .version(); + .version(); \ No newline at end of file From c6e709cd36cd1f5427ba24578401112ed9ffaa32 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 26 Jul 2024 12:45:06 +0100 Subject: [PATCH 31/71] Added parameters Signed-off-by: snipe --- app/Helpers/Helper.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 6166d6668..fcb439f81 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -1530,11 +1530,11 @@ class Helper if ($redirect_option == 'target') { switch ($checkout_to_type) { case 'user': - return route('users.show', $request->assigned_user); + return route('users.show', ['user' => $request->assigned_user]); case 'location': - return route('locations.show', $request->assigned_location); + return route('locations.show', ['location' => $request->assigned_location]); case 'asset': - return route('hardware.show', $request->assigned_asset); + return route('hardware.show', ['hardware' => $request->assigned_asset]); } } return redirect()->back()->with('error', trans('admin/hardware/message.checkout.error')); From 5dea3f44956b1375cfb8d027de8e64746d1cf4a3 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 26 Jul 2024 12:47:33 +0100 Subject: [PATCH 32/71] Added blade component to checkin/checkout pages Signed-off-by: snipe --- resources/views/accessories/checkin.blade.php | 14 +++++++++----- resources/views/accessories/checkout.blade.php | 14 ++++++++++---- resources/views/components/checkin.blade.php | 12 ++++++++---- resources/views/components/checkout.blade.php | 14 ++++++++++---- resources/views/consumables/checkout.blade.php | 12 ++++++++---- resources/views/licenses/checkin.blade.php | 12 ++++++++---- resources/views/licenses/checkout.blade.php | 13 +++++++++---- 7 files changed, 62 insertions(+), 29 deletions(-) diff --git a/resources/views/accessories/checkin.blade.php b/resources/views/accessories/checkin.blade.php index 7d1ef1326..cceb8b895 100755 --- a/resources/views/accessories/checkin.blade.php +++ b/resources/views/accessories/checkin.blade.php @@ -71,11 +71,15 @@ - + diff --git a/resources/views/accessories/checkout.blade.php b/resources/views/accessories/checkout.blade.php index 71035a87c..6c96e1bfa 100755 --- a/resources/views/accessories/checkout.blade.php +++ b/resources/views/accessories/checkout.blade.php @@ -114,10 +114,16 @@ - + diff --git a/resources/views/components/checkin.blade.php b/resources/views/components/checkin.blade.php index e195685d2..d838744ff 100644 --- a/resources/views/components/checkin.blade.php +++ b/resources/views/components/checkin.blade.php @@ -56,10 +56,14 @@ {!! $errors->first('note', '') !!} - + diff --git a/resources/views/components/checkout.blade.php b/resources/views/components/checkout.blade.php index f6befa273..39890a193 100644 --- a/resources/views/components/checkout.blade.php +++ b/resources/views/components/checkout.blade.php @@ -54,10 +54,16 @@ - + diff --git a/resources/views/consumables/checkout.blade.php b/resources/views/consumables/checkout.blade.php index 29b68b6ce..bb3023290 100644 --- a/resources/views/consumables/checkout.blade.php +++ b/resources/views/consumables/checkout.blade.php @@ -106,10 +106,14 @@ - + diff --git a/resources/views/licenses/checkin.blade.php b/resources/views/licenses/checkin.blade.php index 8eeea6f9c..5ef915954 100755 --- a/resources/views/licenses/checkin.blade.php +++ b/resources/views/licenses/checkin.blade.php @@ -56,10 +56,14 @@ {!! $errors->first('notes', '') !!} - + diff --git a/resources/views/licenses/checkout.blade.php b/resources/views/licenses/checkout.blade.php index e85c67742..bfd477309 100755 --- a/resources/views/licenses/checkout.blade.php +++ b/resources/views/licenses/checkout.blade.php @@ -105,10 +105,15 @@ @endif - + From 5d7f1f77a39ec7d5bbb502a3acaf23e96cceceb2 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 26 Jul 2024 12:48:07 +0100 Subject: [PATCH 33/71] Added redirect to checkin/checkout controllers Signed-off-by: snipe --- .../AccessoryCheckinController.php | 5 +++- .../AccessoryCheckoutController.php | 10 +++++++- .../Components/ComponentCheckinController.php | 9 ++++--- .../ComponentCheckoutController.php | 10 ++++++-- .../ConsumableCheckoutController.php | 13 +++++++--- .../Licenses/LicenseCheckinController.php | 9 +++---- .../Licenses/LicenseCheckoutController.php | 24 ++++++++++++++----- 7 files changed, 58 insertions(+), 22 deletions(-) diff --git a/app/Http/Controllers/Accessories/AccessoryCheckinController.php b/app/Http/Controllers/Accessories/AccessoryCheckinController.php index eff635d24..7a228e50a 100644 --- a/app/Http/Controllers/Accessories/AccessoryCheckinController.php +++ b/app/Http/Controllers/Accessories/AccessoryCheckinController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Accessories; use App\Events\CheckoutableCheckedIn; +use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Models\Accessory; use App\Models\User; @@ -63,7 +64,9 @@ class AccessoryCheckinController extends Controller event(new CheckoutableCheckedIn($accessory, User::find($return_to), auth()->user(), $request->input('note'), $checkin_at)); - return redirect()->route('accessories.show', $accessory->id)->with('success', trans('admin/accessories/message.checkin.success')); + session()->put(['redirect_option' => $request->get('redirect_option')]); + + return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))->with('success', trans('admin/accessories/message.checkin.success')); } // Redirect to the accessory management page with error return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.checkin.error')); diff --git a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php index 19c8c6c7c..5b10e99bc 100644 --- a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php +++ b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Accessories; use App\Events\CheckoutableCheckedOut; +use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Http\Requests\AccessoryCheckoutRequest; use App\Models\Accessory; @@ -78,8 +79,15 @@ class AccessoryCheckoutController extends Controller } event(new CheckoutableCheckedOut($accessory, $user, auth()->user(), $request->input('note'))); + // Set this as user since we only allow checkout to user for this item type + $request->request->add(['checkout_to_type' => 'user']); + $request->request->add(['assigned_user' => $user->id]); + + session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); + + // Redirect to the new accessory page - return redirect()->route('accessories.index') + return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories')) ->with('success', trans('admin/accessories/message.checkout.success')); } } diff --git a/app/Http/Controllers/Components/ComponentCheckinController.php b/app/Http/Controllers/Components/ComponentCheckinController.php index b59237a5d..379882c3c 100644 --- a/app/Http/Controllers/Components/ComponentCheckinController.php +++ b/app/Http/Controllers/Components/ComponentCheckinController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers\Components; use App\Events\CheckoutableCheckedIn; use App\Events\ComponentCheckedIn; +use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Models\Asset; use App\Models\Component; @@ -96,12 +97,10 @@ class ComponentCheckinController extends Controller $asset = Asset::find($component_assets->asset_id); event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now())); - if ($backto == 'asset'){ - return redirect()->route('hardware.show', $asset->id)->with('success', - trans('admin/components/message.checkin.success')); - } - return redirect()->route('components.index')->with('success', + session()->put(['redirect_option' => $request->get('redirect_option')]); + + return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.checkin.success')); } diff --git a/app/Http/Controllers/Components/ComponentCheckoutController.php b/app/Http/Controllers/Components/ComponentCheckoutController.php index fc319b47d..85d850357 100644 --- a/app/Http/Controllers/Components/ComponentCheckoutController.php +++ b/app/Http/Controllers/Components/ComponentCheckoutController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers\Components; use App\Events\CheckoutableCheckedOut; use App\Events\ComponentCheckedOut; +use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Models\Asset; use App\Models\Component; @@ -93,7 +94,7 @@ class ComponentCheckoutController extends Controller ->withInput(); } - // Check if the user exists + // Check if the asset exists $asset = Asset::find($request->input('asset_id')); // Update the component data @@ -109,6 +110,11 @@ class ComponentCheckoutController extends Controller event(new CheckoutableCheckedOut($component, $asset, auth()->user(), $request->input('note'))); - return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success')); + $request->request->add(['checkout_to_type' => 'asset']); + $request->request->add(['assigned_asset' => $asset->id]); + + session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); + + return redirect()->to(Helper::getRedirectOption($request, $component->id, 'Components'))->with('success', trans('admin/components/message.checkout.success')); } } diff --git a/app/Http/Controllers/Consumables/ConsumableCheckoutController.php b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php index fd690fede..1bdb16af9 100644 --- a/app/Http/Controllers/Consumables/ConsumableCheckoutController.php +++ b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Consumables; use App\Events\CheckoutableCheckedOut; +use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Models\Consumable; use App\Models\User; @@ -33,7 +34,7 @@ class ConsumableCheckoutController extends Controller // Make sure there is at least one available to checkout if ($consumable->numRemaining() <= 0){ return redirect()->route('consumables.index') - ->with('error', trans('admin/consumables/message.checkout.unavailable')); + ->with('error', trans('admin/consumables/message.checkout.unavailable', ['requested' => 1, 'remaining' => $consumable->numRemaining()])); } // Return the checkout view @@ -76,7 +77,7 @@ class ConsumableCheckoutController extends Controller // Make sure there is at least one available to checkout if ($consumable->numRemaining() <= 0 || $quantity > $consumable->numRemaining()) { - return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable')); + return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable', ['requested' => $quantity, 'remaining' => $consumable->numRemaining() ])); } $admin_user = auth()->user(); @@ -101,7 +102,13 @@ class ConsumableCheckoutController extends Controller } event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note'))); + $request->request->add(['checkout_to_type' => 'user']); + $request->request->add(['assigned_user' => $user->id]); + + session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); + + // Redirect to the new consumable page - return redirect()->route('consumables.index')->with('success', trans('admin/consumables/message.checkout.success')); + return redirect()->to(Helper::getRedirectOption($request, $consumable->id, 'Consumables'))->with('success', trans('admin/consumables/message.checkout.success')); } } diff --git a/app/Http/Controllers/Licenses/LicenseCheckinController.php b/app/Http/Controllers/Licenses/LicenseCheckinController.php index e863aa860..dd83d0154 100644 --- a/app/Http/Controllers/Licenses/LicenseCheckinController.php +++ b/app/Http/Controllers/Licenses/LicenseCheckinController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Licenses; use App\Events\CheckoutableCheckedIn; +use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Models\License; use App\Models\LicenseSeat; @@ -100,15 +101,15 @@ class LicenseCheckinController extends Controller $licenseSeat->asset_id = null; $licenseSeat->notes = $request->input('notes'); + session()->put(['redirect_option' => $request->get('redirect_option')]); + + // Was the asset updated? if ($licenseSeat->save()) { event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes'))); - if ($backTo == 'user') { - return redirect()->route('users.show', $return_to->id)->with('success', trans('admin/licenses/message.checkin.success')); - } - return redirect()->route('licenses.show', $licenseSeat->license_id)->with('success', trans('admin/licenses/message.checkin.success')); + return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.checkin.success')); } // Redirect to the license page with error diff --git a/app/Http/Controllers/Licenses/LicenseCheckoutController.php b/app/Http/Controllers/Licenses/LicenseCheckoutController.php index 2fb0434f6..f08d33f9d 100644 --- a/app/Http/Controllers/Licenses/LicenseCheckoutController.php +++ b/app/Http/Controllers/Licenses/LicenseCheckoutController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Licenses; use App\Events\CheckoutableCheckedOut; +use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Http\Requests\LicenseCheckoutRequest; use App\Models\Accessory; @@ -81,10 +82,23 @@ class LicenseCheckoutController extends Controller $checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type')); - if ($this->$checkoutMethod($licenseSeat)) { - return redirect()->route('licenses.index')->with('success', trans('admin/licenses/message.checkout.success')); + + if (request('checkout_to_type')=='asset') { + $checkoutTarget = $this->checkoutToAsset($licenseSeat); + $request->request->add(['assigned_asset' => $checkoutTarget->id]); + } else { + $checkoutTarget = $this->checkoutToUser($licenseSeat); + $request->request->add(['assigned_user' => $checkoutTarget->id]); } + session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); + + if ($checkoutTarget) { + return redirect()->to(Helper::getRedirectOption($request, $checkoutTarget->id, 'Licenses'))->with('success', trans('admin/licenses/message.checkout.success')); + } + + + return redirect()->route('licenses.index')->with('error', trans('Something went wrong handling this checkout.')); } @@ -120,8 +134,7 @@ class LicenseCheckoutController extends Controller } if ($licenseSeat->save()) { event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes'))); - - return true; + return $target; } return false; @@ -137,8 +150,7 @@ class LicenseCheckoutController extends Controller if ($licenseSeat->save()) { event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes'))); - - return true; + return $target; } return false; From fc8bb82a0295341ea273753f8812b080fd89b379 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 26 Jul 2024 12:48:18 +0100 Subject: [PATCH 34/71] Made dropdown wider Signed-off-by: snipe --- resources/views/blade/redirect_submit_options.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/blade/redirect_submit_options.blade.php b/resources/views/blade/redirect_submit_options.blade.php index f22d55d89..a6b0c7fc8 100644 --- a/resources/views/blade/redirect_submit_options.blade.php +++ b/resources/views/blade/redirect_submit_options.blade.php @@ -17,7 +17,7 @@
@if (($options) && (count($options) > 0)) - @foreach ($options as $key => $value)
@endif + @if ($snipeSettings->qr_code=='1') +
+ QR code for {{ $asset->getDisplayNameAttribute() }} +
+ @endif +

From 28c7355697bab3eaa1b784be6c9560042596b0ae Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 29 Jul 2024 09:52:38 +0100 Subject: [PATCH 44/71] Fixed missing div Signed-off-by: snipe --- resources/views/hardware/view.blade.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index 9fab6d864..2444ae79a 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -306,6 +306,7 @@

+ From b18baf74d2d678cac6247aac1dd7c5f5f75c0bc2 Mon Sep 17 00:00:00 2001 From: arne-kroeger Date: Mon, 29 Jul 2024 10:54:53 +0200 Subject: [PATCH 45/71] added options to checkout accessoires to locations and assets Added #14979: add checkout functionality to accessoires --- app/Console/Commands/RestoreFromBackup.php | 2 +- app/Helpers/Helper.php | 4 +- .../Accessories/AccessoriesController.php | 6 +- .../AccessoryCheckinController.php | 17 +- .../AccessoryCheckoutController.php | 29 ++-- .../Controllers/Api/AccessoriesController.php | 54 +++---- .../Controllers/Users/BulkUsersController.php | 2 +- .../Requests/AccessoryCheckoutRequest.php | 11 +- .../Transformers/AccessoriesTransformer.php | 43 +++-- .../Transformers/ActionlogsTransformer.php | 4 +- app/Models/Accessory.php | 19 ++- app/Models/AccessoryCheckout.php | 148 ++++++++++++++++++ app/Models/User.php | 2 +- app/Presenters/AccessoryPresenter.php | 2 +- database/factories/AccessoryFactory.php | 9 +- ..._checkout_for_all_types_to_accessories.php | 39 +++++ .../views/accessories/checkout.blade.php | 9 +- resources/views/accessories/view.blade.php | 14 +- .../Checkins/Ui/AccessoryCheckinTest.php | 8 +- .../Checkouts/Api/AccessoryCheckoutTest.php | 26 +-- .../Checkouts/Ui/AccessoryCheckoutTest.php | 19 ++- 21 files changed, 347 insertions(+), 120 deletions(-) create mode 100755 app/Models/AccessoryCheckout.php create mode 100644 database/migrations/2024_07_26_143301_add_checkout_for_all_types_to_accessories.php diff --git a/app/Console/Commands/RestoreFromBackup.php b/app/Console/Commands/RestoreFromBackup.php index 3ea696f36..846c2933c 100644 --- a/app/Console/Commands/RestoreFromBackup.php +++ b/app/Console/Commands/RestoreFromBackup.php @@ -92,7 +92,7 @@ class SQLStreamer { $parser->line_aware_piping(); // <----- THIS is doing the heavy lifting! $check_tables = ['settings' => null, 'migrations' => null /* 'assets' => null */]; //TODO - move to statics? - //can't use 'users' because the 'accessories_users' table? + //can't use 'users' because the 'accessories_checkout' table? // can't use 'assets' because 'ver1_components_assets' foreach($check_tables as $check_table => $_ignore) { foreach ($parser->tablenames as $tablename => $_count) { diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index fcb439f81..18e149b57 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -721,7 +721,7 @@ class Helper { $alert_threshold = \App\Models\Setting::getSettings()->alert_threshold; $consumables = Consumable::withCount('consumableAssignments as consumable_assignments_count')->whereNotNull('min_amt')->get(); - $accessories = Accessory::withCount('users as users_count')->whereNotNull('min_amt')->get(); + $accessories = Accessory::withCount('checkouts as checkouts_count')->whereNotNull('min_amt')->get(); $components = Component::whereNotNull('min_amt')->get(); $asset_models = AssetModel::where('min_amt', '>', 0)->get(); $licenses = License::where('min_amt', '>', 0)->get(); @@ -749,7 +749,7 @@ class Helper } foreach ($accessories as $accessory) { - $avail = $accessory->qty - $accessory->users_count; + $avail = $accessory->qty - $accessory->checkouts_count; if ($avail < ($accessory->min_amt) + $alert_threshold) { if ($accessory->qty > 0) { $percent = number_format((($avail / $accessory->qty) * 100), 0); diff --git a/app/Http/Controllers/Accessories/AccessoriesController.php b/app/Http/Controllers/Accessories/AccessoriesController.php index 722638ad8..4fd5a4c54 100755 --- a/app/Http/Controllers/Accessories/AccessoriesController.php +++ b/app/Http/Controllers/Accessories/AccessoriesController.php @@ -144,12 +144,12 @@ class AccessoriesController extends Controller */ public function update(ImageUploadRequest $request, $accessoryId = null) : RedirectResponse { - if ($accessory = Accessory::withCount('users as users_count')->find($accessoryId)) { + if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryId)) { $this->authorize($accessory); $validator = Validator::make($request->all(), [ - "qty" => "required|numeric|min:$accessory->users_count" + "qty" => "required|numeric|min:$accessory->checkouts_count" ]); if ($validator->fails()) { @@ -233,7 +233,7 @@ class AccessoriesController extends Controller */ public function show($accessoryID = null) : View | RedirectResponse { - $accessory = Accessory::withCount('users as users_count')->find($accessoryID); + $accessory = Accessory::withCount('checkouts as checkouts_count')->find($accessoryID); $this->authorize('view', $accessory); if (isset($accessory->id)) { return view('accessories/view', compact('accessory')); diff --git a/app/Http/Controllers/Accessories/AccessoryCheckinController.php b/app/Http/Controllers/Accessories/AccessoryCheckinController.php index 7a228e50a..e36f8a240 100644 --- a/app/Http/Controllers/Accessories/AccessoryCheckinController.php +++ b/app/Http/Controllers/Accessories/AccessoryCheckinController.php @@ -6,6 +6,7 @@ use App\Events\CheckoutableCheckedIn; use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Models\Accessory; +use App\Models\AccessoryCheckout; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -24,7 +25,7 @@ class AccessoryCheckinController extends Controller */ public function create($accessoryUserId = null, $backto = null) : View | RedirectResponse { - if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) { + if (is_null($accessory_user = DB::table('accessories_checkout')->find($accessoryUserId))) { return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.not_found')); } @@ -39,16 +40,16 @@ class AccessoryCheckinController extends Controller * * @uses Accessory::checkin_email() to determine if an email can and should be sent * @author [A. Gianotto] [] - * @param null $accessoryUserId + * @param null $accessoryCheckoutId * @param string $backto */ - public function store(Request $request, $accessoryUserId = null, $backto = null) : RedirectResponse + public function store(Request $request, $accessoryCheckoutId = null, $backto = null) : RedirectResponse { - if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) { + if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryCheckoutId))) { return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist')); } - $accessory = Accessory::find($accessory_user->accessory_id); + $accessory = Accessory::find($accessory_checkout->accessory_id); $this->authorize('checkin', $accessory); @@ -59,10 +60,8 @@ class AccessoryCheckinController extends Controller } // Was the accessory updated? - if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) { - $return_to = e($accessory_user->assigned_to); - - event(new CheckoutableCheckedIn($accessory, User::find($return_to), auth()->user(), $request->input('note'), $checkin_at)); + if ($accessory_checkout->delete()) { + event(new CheckoutableCheckedIn($accessory, $accessory_checkout->assignedTo, auth()->user(), $request->input('note'), $checkin_at)); session()->put(['redirect_option' => $request->get('redirect_option')]); diff --git a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php index 5b10e99bc..03fb6ac25 100644 --- a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php +++ b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php @@ -4,9 +4,11 @@ namespace App\Http\Controllers\Accessories; use App\Events\CheckoutableCheckedOut; use App\Helpers\Helper; +use App\Http\Controllers\CheckInOutRequest; use App\Http\Controllers\Controller; use App\Http\Requests\AccessoryCheckoutRequest; use App\Models\Accessory; +use App\Models\AccessoryCheckout; use App\Models\User; use Carbon\Carbon; use Illuminate\Http\Request; @@ -16,6 +18,9 @@ use \Illuminate\Http\RedirectResponse; class AccessoryCheckoutController extends Controller { + + use CheckInOutRequest; + /** * Return the form to checkout an Accessory to a user. * @@ -25,7 +30,7 @@ class AccessoryCheckoutController extends Controller public function create($id) : View | RedirectResponse { - if ($accessory = Accessory::withCount('users as users_count')->find($id)) { + if ($accessory = Accessory::withCount('checkouts as checkouts_count')->find($id)) { $this->authorize('checkout', $accessory); @@ -58,30 +63,32 @@ class AccessoryCheckoutController extends Controller * * @author [A. Gianotto] [] * @param Request $request - * @param int $accessory + * @param Accessory $accessory */ public function store(AccessoryCheckoutRequest $request, Accessory $accessory) : RedirectResponse { - + $this->authorize('checkout', $accessory); - $accessory->assigned_to = $request->input('assigned_to'); - $user = User::find($request->input('assigned_to')); - $accessory->checkout_qty = $request->input('checkout_qty', 1); + $target = $this->determineCheckoutTarget(); + + $accessory->checkout_qty = $request->input('checkout_qty', 1); + for ($i = 0; $i < $accessory->checkout_qty; $i++) { - $accessory->users()->attach($accessory->id, [ + AccessoryCheckout::create([ 'accessory_id' => $accessory->id, 'created_at' => Carbon::now(), 'user_id' => Auth::id(), - 'assigned_to' => $request->input('assigned_to'), + 'assigned_to' => $target->id, + 'assigned_type' => $target::class, 'note' => $request->input('note'), ]); } - event(new CheckoutableCheckedOut($accessory, $user, auth()->user(), $request->input('note'))); + event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note'))); // Set this as user since we only allow checkout to user for this item type - $request->request->add(['checkout_to_type' => 'user']); - $request->request->add(['assigned_user' => $user->id]); + $request->request->add(['checkout_to_type' => request('checkout_to_type')]); + $request->request->add(['assigned_user' => $target->id]); session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]); diff --git a/app/Http/Controllers/Api/AccessoriesController.php b/app/Http/Controllers/Api/AccessoriesController.php index 1ffdcaf19..12f3f0e54 100644 --- a/app/Http/Controllers/Api/AccessoriesController.php +++ b/app/Http/Controllers/Api/AccessoriesController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api; use App\Events\CheckoutableCheckedOut; use App\Helpers\Helper; +use App\Http\Controllers\CheckInOutRequest; use App\Http\Controllers\Controller; use App\Http\Requests\AccessoryCheckoutRequest; use App\Http\Requests\StoreAccessoryRequest; @@ -17,10 +18,12 @@ use Carbon\Carbon; use Illuminate\Support\Facades\DB; use Illuminate\Http\Request; use App\Http\Requests\ImageUploadRequest; - +use App\Models\AccessoryCheckout; class AccessoriesController extends Controller { + use CheckInOutRequest; + /** * Display a listing of the resource. * @@ -48,13 +51,13 @@ class AccessoriesController extends Controller 'min_amt', 'company_id', 'notes', - 'users_count', + 'checkouts_count', 'qty', ]; - $accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'users', 'location', 'supplier') - ->withCount('users as users_count'); + $accessories = Accessory::select('accessories.*')->with('category', 'company', 'manufacturer', 'checkouts', 'location', 'supplier') + ->withCount('checkouts as checkouts_count'); if ($request->filled('search')) { $accessories = $accessories->TextSearch($request->input('search')); @@ -154,7 +157,7 @@ class AccessoriesController extends Controller public function show($id) { $this->authorize('view', Accessory::class); - $accessory = Accessory::withCount('users as users_count')->findOrFail($id); + $accessory = Accessory::withCount('checkouts as checkouts_count')->findOrFail($id); return (new AccessoriesTransformer)->transformAccessory($accessory); } @@ -197,28 +200,23 @@ class AccessoriesController extends Controller $offset = request('offset', 0); $limit = request('limit', 50); - $accessory_users = $accessory->users; - $total = $accessory_users->count(); + $accessory_checkouts = $accessory->checkouts; + $total = $accessory_checkouts->count(); if ($total < $offset) { $offset = 0; } - $accessory_users = $accessory->users()->skip($offset)->take($limit)->get(); + $accessory_checkouts = $accessory->checkouts()->skip($offset)->take($limit)->get(); if ($request->filled('search')) { - $accessory_users = $accessory->users() - ->where(function ($query) use ($request) { - $search_str = '%' . $request->input('search') . '%'; - $query->where('first_name', 'like', $search_str) - ->orWhere('last_name', 'like', $search_str) - ->orWhere('note', 'like', $search_str); - }) + + $accessory_checkouts = $accessory->checkouts()->TextSearch($request->input('search')) ->get(); - $total = $accessory_users->count(); + $total = $accessory_checkouts->count(); } - return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_users, $total); + return (new AccessoriesTransformer)->transformCheckedoutAccessory($accessory, $accessory_checkouts, $total); } @@ -282,22 +280,22 @@ class AccessoriesController extends Controller public function checkout(AccessoryCheckoutRequest $request, Accessory $accessory) { $this->authorize('checkout', $accessory); - $accessory->assigned_to = $request->input('assigned_to'); - $user = User::find($request->input('assigned_to')); + $target = $this->determineCheckoutTarget(); $accessory->checkout_qty = $request->input('checkout_qty', 1); for ($i = 0; $i < $accessory->checkout_qty; $i++) { - $accessory->users()->attach($accessory->id, [ + AccessoryCheckout::create([ 'accessory_id' => $accessory->id, 'created_at' => Carbon::now(), 'user_id' => Auth::id(), - 'assigned_to' => $request->input('assigned_to'), + 'assigned_to' => $target->id, + 'assigned_type' => $target::class, 'note' => $request->input('note'), ]); } // Set this value to be able to pass the qty through to the event - event(new CheckoutableCheckedOut($accessory, $user, auth()->user(), $request->input('note'))); + event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note'))); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success'))); @@ -316,19 +314,19 @@ class AccessoriesController extends Controller */ public function checkin(Request $request, $accessoryUserId = null) { - if (is_null($accessory_user = DB::table('accessories_users')->find($accessoryUserId))) { + if (is_null($accessory_checkout = DB::table('accessories_checkout')->find($accessoryUserId))) { return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist'))); } - $accessory = Accessory::find($accessory_user->accessory_id); + $accessory = Accessory::find($accessory_checkout->accessory_id); $this->authorize('checkin', $accessory); - $logaction = $accessory->logCheckin(User::find($accessory_user->assigned_to), $request->input('note')); + $logaction = $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note')); // Was the accessory updated? - if (DB::table('accessories_users')->where('id', '=', $accessory_user->id)->delete()) { - if (! is_null($accessory_user->assigned_to)) { - $user = User::find($accessory_user->assigned_to); + if (DB::table('accessories_checkout')->where('id', '=', $accessory_checkout->id)->delete()) { + if (! is_null($accessory_checkout->assigned_to)) { + $user = User::find($accessory_checkout->assigned_to); } $data['log_id'] = $logaction->id; diff --git a/app/Http/Controllers/Users/BulkUsersController.php b/app/Http/Controllers/Users/BulkUsersController.php index b0683e2cb..fcd295ca6 100644 --- a/app/Http/Controllers/Users/BulkUsersController.php +++ b/app/Http/Controllers/Users/BulkUsersController.php @@ -219,7 +219,7 @@ class BulkUsersController extends Controller $users = User::whereIn('id', $user_raw_array)->get(); $assets = Asset::whereIn('assigned_to', $user_raw_array)->where('assigned_type', \App\Models\User::class)->get(); - $accessories = DB::table('accessories_users')->whereIn('assigned_to', $user_raw_array)->get(); + $accessories = DB::table('accessories_checkout')->whereIn('assigned_to', $user_raw_array)->get(); $licenses = DB::table('license_seats')->whereIn('assigned_to', $user_raw_array)->get(); $consumables = DB::table('consumables_users')->whereIn('assigned_to', $user_raw_array)->get(); diff --git a/app/Http/Requests/AccessoryCheckoutRequest.php b/app/Http/Requests/AccessoryCheckoutRequest.php index 0e17b390c..deda07f8f 100644 --- a/app/Http/Requests/AccessoryCheckoutRequest.php +++ b/app/Http/Requests/AccessoryCheckoutRequest.php @@ -44,13 +44,10 @@ class AccessoryCheckoutRequest extends ImageUploadRequest return array_merge( [ - 'assigned_to' => [ - 'required', - 'integer', - 'exists:users,id,deleted_at,NULL', - 'not_array' - ], - + 'assigned_user' => 'required_without_all:assigned_asset,assigned_location', + 'assigned_asset' => 'required_without_all:assigned_user,assigned_location', + 'assigned_location' => 'required_without_all:assigned_user,assigned_asset', + 'number_remaining_after_checkout' => [ 'min:0', 'required', diff --git a/app/Http/Transformers/AccessoriesTransformer.php b/app/Http/Transformers/AccessoriesTransformer.php index 7b79973a9..c85c4e86f 100644 --- a/app/Http/Transformers/AccessoriesTransformer.php +++ b/app/Http/Transformers/AccessoriesTransformer.php @@ -39,7 +39,7 @@ class AccessoriesTransformer 'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null, 'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null, 'remaining_qty' => (int) $accessory->numRemaining(), - 'users_count' => $accessory->users_count, + 'checkouts_count' => $accessory->checkouts_count, 'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'), @@ -66,27 +66,42 @@ class AccessoriesTransformer return $array; } - public function transformCheckedoutAccessory($accessory, $accessory_users, $total) + public function transformCheckedoutAccessory($accessory, $accessory_checkouts, $total) { $array = []; - foreach ($accessory_users as $user) { + foreach ($accessory_checkouts as $checkout) { $array[] = [ - - 'assigned_pivot_id' => $user->pivot->id, - 'id' => (int) $user->id, - 'username' => e($user->username), - 'name' => e($user->getFullNameAttribute()), - 'first_name'=> e($user->first_name), - 'last_name'=> e($user->last_name), - 'employee_number' => e($user->employee_num), - 'checkout_notes' => e($user->pivot->note), - 'last_checkout' => Helper::getFormattedDateObject($user->pivot->created_at, 'datetime'), - 'type' => 'user', + 'id' => $checkout->id, + 'assigned_to' => $this->transformAssignedTo($checkout), + 'checkout_notes' => e($checkout->note), + 'last_checkout' => Helper::getFormattedDateObject($checkout->created_at, 'datetime'), 'available_actions' => ['checkin' => true], ]; } return (new DatatablesTransformer)->transformDatatables($array, $total); } + + public function transformAssignedTo($accessoryCheckout) + { + if ($accessoryCheckout->checkedOutToUser()) { + return [ + 'id' => (int) $accessoryCheckout->assigned->id, + 'username' => e($accessoryCheckout->assigned->username), + 'name' => e($accessoryCheckout->assigned->getFullNameAttribute()), + 'first_name'=> e($accessoryCheckout->assigned->first_name), + 'last_name'=> ($accessoryCheckout->assigned->last_name) ? e($accessoryCheckout->assigned->last_name) : null, + 'email'=> ($accessoryCheckout->assigned->email) ? e($accessoryCheckout->assigned->email) : null, + 'employee_number' => ($accessoryCheckout->assigned->employee_num) ? e($accessoryCheckout->assigned->employee_num) : null, + 'type' => 'user', + ]; + } + + return $accessoryCheckout->assigned ? [ + 'id' => $accessoryCheckout->assigned->id, + 'name' => e($accessoryCheckout->assigned->display_name), + 'type' => $accessoryCheckout->assignedType(), + ] : null; + } } diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php index 8a09cc840..96d74827d 100644 --- a/app/Http/Transformers/ActionlogsTransformer.php +++ b/app/Http/Transformers/ActionlogsTransformer.php @@ -205,11 +205,11 @@ class ActionlogsTransformer - public function transformCheckedoutActionlog (Collection $accessories_users, $total) + public function transformCheckedoutActionlog (Collection $accessories_checkout, $total) { $array = array(); - foreach ($accessories_users as $user) { + foreach ($accessories_checkout as $user) { $array[] = (new UsersTransformer)->transformUser($user); } return (new DatatablesTransformer)->transformDatatables($array, $total); diff --git a/app/Models/Accessory.php b/app/Models/Accessory.php index 20d2584c3..c1366f67e 100755 --- a/app/Models/Accessory.php +++ b/app/Models/Accessory.php @@ -253,9 +253,10 @@ class Accessory extends SnipeModel * @since [v3.0] * @return \Illuminate\Database\Eloquent\Relations\Relation */ - public function users() + public function checkouts() { - return $this->belongsToMany(\App\Models\User::class, 'accessories_users', 'accessory_id', 'assigned_to')->withPivot('id', 'created_at', 'note')->withTrashed(); + return $this->hasMany(\App\Models\AccessoryCheckout::class, 'accessory_id') + ->with('assignedTo'); } /** @@ -267,7 +268,9 @@ class Accessory extends SnipeModel */ public function hasUsers() { - return $this->belongsToMany(\App\Models\User::class, 'accessories_users', 'accessory_id', 'assigned_to')->count(); + return $this->hasMany(\App\Models\AccessoryCheckout::class, 'accessory_id') + ->where('assigned_type', User::class) + ->count(); } /** @@ -338,15 +341,15 @@ class Accessory extends SnipeModel */ public function numCheckedOut() { - return $this->users_count ?? $this->users()->count(); + return $this->checkouts_count ?? $this->checkouts()->count(); } /** * Check how many items of an accessory remain. * - * In order to use this model method, you MUST call withCount('users as users_count') - * on the eloquent query in the controller, otherwise $this->users_count will be null and + * In order to use this model method, you MUST call withCount('checkouts as checkouts_count') + * on the eloquent query in the controller, otherwise $this->checkouts_count will be null and * bad things happen. * * @author [A. Gianotto] [] @@ -370,12 +373,12 @@ class Accessory extends SnipeModel */ public function declinedCheckout(User $declinedBy, $signature) { - if (is_null($accessory_user = \DB::table('accessories_users')->where('assigned_to', $declinedBy->id)->where('accessory_id', $this->id)->latest('created_at'))) { + if (is_null($accessory_checkout = AccessoryCheckout::userAssigned()->where('assigned_to', $declinedBy->id)->where('accessory_id', $this->id)->latest('created_at'))) { // Redirect to the accessory management page with error return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist')); } - $accessory_user->limit(1)->delete(); + $accessory_checkout->limit(1)->delete(); } /** diff --git a/app/Models/AccessoryCheckout.php b/app/Models/AccessoryCheckout.php new file mode 100755 index 000000000..7f42b354e --- /dev/null +++ b/app/Models/AccessoryCheckout.php @@ -0,0 +1,148 @@ + accessory relationship + * + * @author [A. Kroeger] + * @since [v7.0.9] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function accessory() + { + return $this->hasOne(\App\Models\Accessory::class, 'accessory_id'); + } + + /** + * Establishes the accessory checkout -> user relationship + * + * @author [A. Kroeger] + * @since [v7.0.9] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function user() + { + return $this->hasOne(\App\Models\User::class, 'user_id'); + } + + /** + * Get the target this asset is checked out to + * + * @author [A. Kroeger] + * @since [v7.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function assignedTo() + { + return $this->morphTo('assigned', 'assigned_type', 'assigned_to')->withTrashed(); + } + + /** + * Gets the lowercased name of the type of target the asset is assigned to + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string + */ + public function assignedType() + { + return $this->assigned_type ? strtolower(class_basename($this->assigned_type)) : null; + } + + /** + * Determines whether the accessory is checked out to a user + * + * Even though we allow allow for checkout to things beyond users + * this method is an easy way of seeing if we are checked out to a user. + * + * @author [A. Kroeger] + * @since [v7.0] + */ + public function checkedOutToUser(): bool + { + return $this->assignedType() === Asset::USER; + } + + public function scopeUserAssigned(Builder $query): void + { + $query->where('assigned_type', '=', User::class); + } + + /** + * Run additional, advanced searches. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param array $terms The search terms + * @return \Illuminate\Database\Eloquent\Builder + */ + public function advancedTextSearch(Builder $query, array $terms) + { + + $userQuery = User::where(function ($query) use ($terms) { + foreach ($terms as $term) { + $search_str = '%' . $term . '%'; + $query->where('first_name', 'like', $search_str) + ->orWhere('last_name', 'like', $search_str) + ->orWhere('note', 'like', $search_str); + } + })->select('id'); + + $locationQuery = Location::where(function ($query) use ($terms) { + foreach ($terms as $term) { + $search_str = '%' . $term . '%'; + $query->where('name', 'like', $search_str); + } + })->select('id'); + + $assetQuery = Asset::where(function ($query) use ($terms) { + foreach ($terms as $term) { + $search_str = '%' . $term . '%'; + $query->where('name', 'like', $search_str); + } + })->select('id'); + + $query->where(function ($query) use ($userQuery) { + $query->where('assigned_type', User::class) + ->whereIn('assigned_to', $userQuery); + })->orWhere(function($query) use ($locationQuery) { + $query->where('assigned_type', Location::class) + ->whereIn('assigned_to', $locationQuery); + })->orWhere(function($query) use ($assetQuery) { + $query->where('assigned_type', Asset::class) + ->whereIn('assigned_to', $assetQuery); + })->orWhere(function($query) use ($terms) { + foreach ($terms as $term) { + $search_str = '%' . $term . '%'; + $query->where('note', 'like', $search_str); + } + }); + + return $query; + } + + +} diff --git a/app/Models/User.php b/app/Models/User.php index a93eb2656..c03b0d33c 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -331,7 +331,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo */ public function accessories() { - return $this->belongsToMany(\App\Models\Accessory::class, 'accessories_users', 'assigned_to', 'accessory_id') + return $this->belongsToMany(\App\Models\Accessory::class, 'accessories_checkout', 'assigned_to', 'accessory_id') ->withPivot('id', 'created_at', 'note')->withTrashed()->orderBy('accessory_id'); } diff --git a/app/Presenters/AccessoryPresenter.php b/app/Presenters/AccessoryPresenter.php index fd6122cab..4ff3c699c 100644 --- a/app/Presenters/AccessoryPresenter.php +++ b/app/Presenters/AccessoryPresenter.php @@ -90,7 +90,7 @@ class AccessoryPresenter extends Presenter 'visible' => false, 'title' => trans('admin/accessories/general.remaining'), ],[ - 'field' => 'users_count', + 'field' => 'checkouts_count', 'searchable' => false, 'sortable' => true, 'visible' => true, diff --git a/database/factories/AccessoryFactory.php b/database/factories/AccessoryFactory.php index ce0d60cc1..356b367ec 100644 --- a/database/factories/AccessoryFactory.php +++ b/database/factories/AccessoryFactory.php @@ -3,6 +3,7 @@ namespace Database\Factories; use App\Models\Accessory; +use App\Models\AccessoryCheckout; use App\Models\Category; use App\Models\Location; use App\Models\Manufacturer; @@ -125,11 +126,12 @@ class AccessoryFactory extends Factory })->afterCreating(function ($accessory) { $user = User::factory()->create(); - $accessory->users()->attach($accessory->id, [ + $accessory->checkouts()->create([ 'accessory_id' => $accessory->id, - 'created_at' => now(), + 'created_at' => Carbon::now(), 'user_id' => $user->id, 'assigned_to' => $user->id, + 'assigned_type' => User::class, 'note' => '', ]); }); @@ -145,11 +147,12 @@ class AccessoryFactory extends Factory public function checkedOutToUser(User $user = null) { return $this->afterCreating(function (Accessory $accessory) use ($user) { - $accessory->users()->attach($accessory->id, [ + $accessory->checkouts()->create([ 'accessory_id' => $accessory->id, 'created_at' => Carbon::now(), 'user_id' => 1, 'assigned_to' => $user->id ?? User::factory()->create()->id, + 'assigned_type' => User::class, ]); }); } diff --git a/database/migrations/2024_07_26_143301_add_checkout_for_all_types_to_accessories.php b/database/migrations/2024_07_26_143301_add_checkout_for_all_types_to_accessories.php new file mode 100644 index 000000000..41c4e506f --- /dev/null +++ b/database/migrations/2024_07_26_143301_add_checkout_for_all_types_to_accessories.php @@ -0,0 +1,39 @@ +string('assigned_type')->nullable(); + } + }); + } + + DB::update('update '.DB::getTablePrefix().'accessories_checkout set assigned_type = \'App\\\\Models\\\\User\' where assigned_type is null', []); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + if (Schema::hasTable('accessories_checkout')) { + Schema::rename('accessories_checkout', 'accessories_users'); + } + } +}; diff --git a/resources/views/accessories/checkout.blade.php b/resources/views/accessories/checkout.blade.php index 6c96e1bfa..0fe6abec3 100755 --- a/resources/views/accessories/checkout.blade.php +++ b/resources/views/accessories/checkout.blade.php @@ -66,7 +66,14 @@ - @include ('partials.forms.edit.user-select', ['translated_name' => trans('general.select_user'), 'fieldname' => 'assigned_to', 'required'=> 'true']) + @include ('partials.forms.checkout-selector', ['user_select' => 'true','asset_select' => 'true', 'location_select' => 'true']) + + @include ('partials.forms.edit.user-select', ['translated_name' => trans('general.select_user'), 'fieldname' => 'assigned_user', 'required'=> 'true']) + + + @include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.asset'), 'fieldname' => 'assigned_asset', 'unselect' => 'true', 'style' => 'display:none;', 'required'=>'true']) + + @include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'assigned_location', 'style' => 'display:none;', 'required'=>'true'])
diff --git a/resources/views/accessories/view.blade.php b/resources/views/accessories/view.blade.php index e42439bd8..f3add91d4 100644 --- a/resources/views/accessories/view.blade.php +++ b/resources/views/accessories/view.blade.php @@ -68,9 +68,9 @@
name) }}-checkouts-{{ date('Y-m-d') }}", "ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"] }'> - + @@ -314,7 +314,7 @@ {{ trans('general.checked_out') }}
- {{ $accessory->users_count }} + {{ $accessory->checkouts_count }}
@@ -337,7 +337,7 @@ @endcan @can('delete', $accessory) - @if ($accessory->users_count == 0) + @if ($accessory->checkouts_count == 0)
@endcan @@ -296,18 +296,20 @@ @endif - + @endif - @if ($snipeSettings->qr_code=='1') -
- QR code for {{ $asset->getDisplayNameAttribute() }} -
- @endif + @if ($snipeSettings->qr_code=='1') +
+ QR code for {{ $asset->getDisplayNameAttribute() }} +
+ @endif -

- +

+ + +
From 1c1101aeac61845b8560e4ef4a8f7d97d347356e Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 29 Jul 2024 14:26:18 +0100 Subject: [PATCH 48/71] Use the pwd_secure_min value (plus 5) for generated password Signed-off-by: snipe --- resources/views/users/edit.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index 200acb552..e3f691f15 100755 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -678,7 +678,7 @@ $(document).ready(function() { 'bind': 'click', 'passwordElement': '#password', 'displayElement': '#generated-password', - 'passwordLength': 16, + 'passwordLength': {{ ($settings->pwd_secure_min + 5) }}, 'uppercase': true, 'lowercase': true, 'numbers': true, From a77ece01a6cff52025deff52dc79fb44d6d2c9d4 Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 29 Jul 2024 14:34:10 +0100 Subject: [PATCH 49/71] Fixed test name Signed-off-by: snipe --- tests/Feature/Checkouts/Ui/ComponentsCheckoutTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Feature/Checkouts/Ui/ComponentsCheckoutTest.php b/tests/Feature/Checkouts/Ui/ComponentsCheckoutTest.php index 9948de7ed..da285bebb 100644 --- a/tests/Feature/Checkouts/Ui/ComponentsCheckoutTest.php +++ b/tests/Feature/Checkouts/Ui/ComponentsCheckoutTest.php @@ -7,7 +7,7 @@ use App\Models\Component; use App\Models\User; use Tests\TestCase; -class ComponentCheckoutTest extends TestCase +class ComponentsCheckoutTest extends TestCase { public function testCheckingOutComponentRequiresCorrectPermission() { From e8d0147075912d9041f6d99fc8172f7b5f26e139 Mon Sep 17 00:00:00 2001 From: arne-kroeger Date: Mon, 29 Jul 2024 19:04:10 +0200 Subject: [PATCH 50/71] Adjusted missing down on migration and code smells --- app/Http/Controllers/Api/AccessoriesController.php | 4 ++-- ...07_26_143301_add_checkout_for_all_types_to_accessories.php | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Api/AccessoriesController.php b/app/Http/Controllers/Api/AccessoriesController.php index 12f3f0e54..b1506e4f4 100644 --- a/app/Http/Controllers/Api/AccessoriesController.php +++ b/app/Http/Controllers/Api/AccessoriesController.php @@ -314,7 +314,7 @@ class AccessoriesController extends Controller */ public function checkin(Request $request, $accessoryUserId = null) { - if (is_null($accessory_checkout = DB::table('accessories_checkout')->find($accessoryUserId))) { + if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryUserId))) { return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist'))); } @@ -324,7 +324,7 @@ class AccessoriesController extends Controller $logaction = $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note')); // Was the accessory updated? - if (DB::table('accessories_checkout')->where('id', '=', $accessory_checkout->id)->delete()) { + if ($accessory_checkout->delete()) { if (! is_null($accessory_checkout->assigned_to)) { $user = User::find($accessory_checkout->assigned_to); } diff --git a/database/migrations/2024_07_26_143301_add_checkout_for_all_types_to_accessories.php b/database/migrations/2024_07_26_143301_add_checkout_for_all_types_to_accessories.php index 41c4e506f..bde3bc2c2 100644 --- a/database/migrations/2024_07_26_143301_add_checkout_for_all_types_to_accessories.php +++ b/database/migrations/2024_07_26_143301_add_checkout_for_all_types_to_accessories.php @@ -33,6 +33,10 @@ return new class extends Migration public function down(): void { if (Schema::hasTable('accessories_checkout')) { + Schema::table('accessories_checkout', function (Blueprint $table) { + $table->dropColumn('assigned_type'); + }); + Schema::rename('accessories_checkout', 'accessories_users'); } } From 3c3b922eaeccf1d0a632d39dce90708b352f9ecf Mon Sep 17 00:00:00 2001 From: arne-kroeger Date: Mon, 29 Jul 2024 19:15:01 +0200 Subject: [PATCH 51/71] Adjusted newly added tests to new checkout form --- tests/Feature/Checkouts/Ui/AccessoryCheckoutTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/Feature/Checkouts/Ui/AccessoryCheckoutTest.php b/tests/Feature/Checkouts/Ui/AccessoryCheckoutTest.php index a2f4697ea..d4818ffc4 100644 --- a/tests/Feature/Checkouts/Ui/AccessoryCheckoutTest.php +++ b/tests/Feature/Checkouts/Ui/AccessoryCheckoutTest.php @@ -207,7 +207,8 @@ class AccessoryCheckoutTest extends TestCase $this->actingAs(User::factory()->admin()->create()) ->from(route('accessories.index')) ->post(route('accessories.checkout.store', $accessory), [ - 'assigned_to' => User::factory()->create()->id, + 'assigned_user' => User::factory()->create()->id, + 'checkout_to_type' => 'user', 'redirect_option' => 'index', 'assigned_qty' => 1, ]) @@ -222,7 +223,8 @@ class AccessoryCheckoutTest extends TestCase $this->actingAs(User::factory()->admin()->create()) ->from(route('accessories.index')) ->post(route('accessories.checkout.store' , $accessory), [ - 'assigned_to' => User::factory()->create()->id, + 'assigned_user' => User::factory()->create()->id, + 'checkout_to_type' => 'user', 'redirect_option' => 'item', 'assigned_qty' => 1, ]) @@ -239,7 +241,8 @@ class AccessoryCheckoutTest extends TestCase $this->actingAs(User::factory()->admin()->create()) ->from(route('accessories.index')) ->post(route('accessories.checkout.store' , $accessory), [ - 'assigned_to' => $user->id, + 'assigned_user' => $user->id, + 'checkout_to_type' => 'user', 'redirect_option' => 'target', 'assigned_qty' => 1, ]) From 33b86057d19976f135164765b10eb8798d27d1f7 Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 29 Jul 2024 18:27:01 +0100 Subject: [PATCH 52/71] Version bump 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 2713cc35c..f419bf1bd 100644 --- a/config/version.php +++ b/config/version.php @@ -1,10 +1,10 @@ 'v7.0.9', - 'full_app_version' => 'v7.0.9 - build 14485-ga98ad76c6', - 'build_version' => '14485', + 'app_version' => 'v7.0.10', + 'full_app_version' => 'v7.0.10 - build 14684-gc2bcc2e2d', + 'build_version' => '14684', 'prerelease_version' => '', - 'hash_version' => 'ga98ad76c6', - 'full_hash' => 'v7.0.9-112-ga98ad76c6', + 'hash_version' => 'gc2bcc2e2d', + 'full_hash' => 'v7.0.10-311-gc2bcc2e2d', 'branch' => 'develop', ); \ No newline at end of file From 86049624c76f703ada13b5b6bdb56766f25b595c Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Mon, 29 Jul 2024 10:42:26 -0700 Subject: [PATCH 53/71] retargeted new label engine to correct 1d column --- app/View/Label.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/View/Label.php b/app/View/Label.php index ee734fd98..886830659 100644 --- a/app/View/Label.php +++ b/app/View/Label.php @@ -107,7 +107,7 @@ class Label implements View if ($settings->alt_barcode_enabled) { if ($template->getSupport1DBarcode()) { - $barcode1DType = $settings->alt_barcode; + $barcode1DType = $settings->label2_1d_type; if ($barcode1DType != 'none') { $assetData->put('barcode1d', (object)[ 'type' => $barcode1DType, From f3d98f90c0592151133b23ae77b327869e8815f0 Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 29 Jul 2024 18:51:12 +0100 Subject: [PATCH 54/71] Add @arne-kroeger as a contributor --- .all-contributorsrc | 9 +++++++++ CONTRIBUTORS.md | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index fe7e73ccb..ec5db5021 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3172,6 +3172,15 @@ "contributions": [ "code" ] + }, + { + "login": "arne-kroeger", + "name": "arne-kroeger", + "avatar_url": "https://avatars.githubusercontent.com/u/65785975?v=4", + "profile": "https://github.com/arne-kroeger", + "contributions": [ + "code" + ] } ] } diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 298d21b8b..0e4efc974 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -51,7 +51,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken | [
NojoudAlshehri](https://github.com/NojoudAlshehri)
[💻](https://github.com/snipe/snipe-it/commits?author=NojoudAlshehri "Code") | [
Stefan Stidl](https://github.com/stefanstidlffg)
[💻](https://github.com/snipe/snipe-it/commits?author=stefanstidlffg "Code") | [
Quentin Aymard](https://github.com/qay21)
[💻](https://github.com/snipe/snipe-it/commits?author=qay21 "Code") | [
Grant Le Roux](https://github.com/cram42)
[💻](https://github.com/snipe/snipe-it/commits?author=cram42 "Code") | [
Bogdan](http://@singrity)
[💻](https://github.com/snipe/snipe-it/commits?author=Singrity "Code") | [
mmanjos](https://github.com/mmanjos)
[💻](https://github.com/snipe/snipe-it/commits?author=mmanjos "Code") | [
Abdelaziz Faki](https://azooz2014.github.io/)
[💻](https://github.com/snipe/snipe-it/commits?author=Azooz2014 "Code") | | [
bilias](https://github.com/bilias)
[💻](https://github.com/snipe/snipe-it/commits?author=bilias "Code") | [
coach1988](https://github.com/coach1988)
[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [
MrM](https://github.com/mauro-miatello)
[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [
koiakoia](https://github.com/koiakoia)
[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [
Mustafa Online](https://github.com/mustafa-online)
[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [
franceslui](https://github.com/franceslui)
[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [
Q4kK](https://github.com/Q4kK)
[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") | | [
squintfox](https://github.com/squintfox)
[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | [
Jeff Clay](https://github.com/jeffclay)
[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [
Phil J R](https://github.com/PP-JN-RL)
[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [
i_virus](https://www.corelight.com/)
[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [
Paul Grime](https://github.com/gitgrimbo)
[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [
Lee Porte](https://leeporte.co.uk)
[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [
BRYAN ](https://github.com/bryanlopezinc)
[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") | -| [
U-H-T](https://github.com/U-H-T)
[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [
Matt Tyree](https://github.com/Tyree)
[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [
Florent Bervas](http://spoontux.net)
[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [
Daniel Albertsen](https://ditscheri.com)
[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [
r-xyz](https://github.com/r-xyz)
[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [
Steven Mainor](https://github.com/DrekiDegga)
[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | +| [
U-H-T](https://github.com/U-H-T)
[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | [
Matt Tyree](https://github.com/Tyree)
[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [
Florent Bervas](http://spoontux.net)
[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [
Daniel Albertsen](https://ditscheri.com)
[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [
r-xyz](https://github.com/r-xyz)
[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [
Steven Mainor](https://github.com/DrekiDegga)
[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [
arne-kroeger](https://github.com/arne-kroeger)
[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! From 4971c54b0530b3905f1a9b02be001a60eefd0acf Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 29 Jul 2024 20:17:25 +0100 Subject: [PATCH 55/71] Fixed seeder Signed-off-by: snipe --- database/seeders/AccessorySeeder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/seeders/AccessorySeeder.php b/database/seeders/AccessorySeeder.php index 31f0c478d..2330a9973 100644 --- a/database/seeders/AccessorySeeder.php +++ b/database/seeders/AccessorySeeder.php @@ -16,7 +16,7 @@ class AccessorySeeder extends Seeder public function run() { Accessory::truncate(); - DB::table('accessories_users')->truncate(); + DB::table('accessories_checkout')->truncate(); if (! Location::count()) { $this->call(LocationSeeder::class); From e395ee1878cefbb216d4cbd1cb2aab2872d42c8b Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Mon, 29 Jul 2024 15:12:32 -0700 Subject: [PATCH 56/71] adds a try catch --- app/Console/Commands/Purge.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/app/Console/Commands/Purge.php b/app/Console/Commands/Purge.php index 8922519c2..08ef7034e 100644 --- a/app/Console/Commands/Purge.php +++ b/app/Console/Commands/Purge.php @@ -143,15 +143,20 @@ class Purge extends Command $this->info($users->count().' users purged.'); $user_assoc = 0; foreach ($users as $user) { + $rel_path = 'private_uploads/users'; $filenames = Actionlog::where('action_type', 'uploaded') ->where('item_id', $user->id) ->pluck('filename'); foreach($filenames as $filename) { - if (Storage::exists($rel_path.'/'.$filename)) { - Storage::delete($rel_path . '/' . $filename); - } - } + try{ + if (Storage::exists($rel_path.'/'.$filename)) { + Storage::delete($rel_path . '/' . $filename); + } + } catch (\Exception $e) { + // Handle the exception or log it + Log::error('An error occurred while deleting files: ' . $e->getMessage()); + } $this->info('- User "'.$user->username.'" deleted.'); $user_assoc += $user->userlog()->count(); $user->userlog()->forceDelete(); From f9a47c8a9fc8e61ae645b5d785500f59742e814b Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Mon, 29 Jul 2024 15:12:48 -0700 Subject: [PATCH 57/71] adds a try catch --- app/Console/Commands/Purge.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Console/Commands/Purge.php b/app/Console/Commands/Purge.php index 08ef7034e..b0055436f 100644 --- a/app/Console/Commands/Purge.php +++ b/app/Console/Commands/Purge.php @@ -16,6 +16,7 @@ use App\Models\Statuslabel; use App\Models\Supplier; use App\Models\User; use Illuminate\Console\Command; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; class Purge extends Command From d46f9776fe3a310e06d864ea539f4ec604462bbc Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Mon, 29 Jul 2024 15:14:58 -0700 Subject: [PATCH 58/71] remove text --- app/Console/Commands/Purge.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Console/Commands/Purge.php b/app/Console/Commands/Purge.php index b0055436f..5ded3917c 100644 --- a/app/Console/Commands/Purge.php +++ b/app/Console/Commands/Purge.php @@ -155,7 +155,6 @@ class Purge extends Command Storage::delete($rel_path . '/' . $filename); } } catch (\Exception $e) { - // Handle the exception or log it Log::error('An error occurred while deleting files: ' . $e->getMessage()); } $this->info('- User "'.$user->username.'" deleted.'); From 89d375daad337b03b1d239525d3fbcc843b509bf Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Mon, 29 Jul 2024 15:15:41 -0700 Subject: [PATCH 59/71] add indents --- app/Console/Commands/Purge.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Console/Commands/Purge.php b/app/Console/Commands/Purge.php index 5ded3917c..35bbe6e9d 100644 --- a/app/Console/Commands/Purge.php +++ b/app/Console/Commands/Purge.php @@ -155,8 +155,8 @@ class Purge extends Command Storage::delete($rel_path . '/' . $filename); } } catch (\Exception $e) { - Log::error('An error occurred while deleting files: ' . $e->getMessage()); - } + Log::error('An error occurred while deleting files: ' . $e->getMessage()); + } $this->info('- User "'.$user->username.'" deleted.'); $user_assoc += $user->userlog()->count(); $user->userlog()->forceDelete(); From 53ad312700d982b6100b49f18f2aa10f3cc48a7e Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Mon, 29 Jul 2024 15:17:32 -0700 Subject: [PATCH 60/71] added missing closing bracket --- app/Console/Commands/Purge.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/Console/Commands/Purge.php b/app/Console/Commands/Purge.php index 35bbe6e9d..5c8c9be9f 100644 --- a/app/Console/Commands/Purge.php +++ b/app/Console/Commands/Purge.php @@ -150,13 +150,14 @@ class Purge extends Command ->where('item_id', $user->id) ->pluck('filename'); foreach($filenames as $filename) { - try{ - if (Storage::exists($rel_path.'/'.$filename)) { + try { + if (Storage::exists($rel_path . '/' . $filename)) { Storage::delete($rel_path . '/' . $filename); } - } catch (\Exception $e) { - Log::error('An error occurred while deleting files: ' . $e->getMessage()); - } + } catch (\Exception $e) { + Log::error('An error occurred while deleting files: ' . $e->getMessage()); + } + } $this->info('- User "'.$user->username.'" deleted.'); $user_assoc += $user->userlog()->count(); $user->userlog()->forceDelete(); From f19899543d7a108b37f1439235164c8412b4846d Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Tue, 30 Jul 2024 09:18:17 -0700 Subject: [PATCH 61/71] changed error to info --- app/Console/Commands/Purge.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Console/Commands/Purge.php b/app/Console/Commands/Purge.php index 5c8c9be9f..1dd2aaa51 100644 --- a/app/Console/Commands/Purge.php +++ b/app/Console/Commands/Purge.php @@ -155,7 +155,7 @@ class Purge extends Command Storage::delete($rel_path . '/' . $filename); } } catch (\Exception $e) { - Log::error('An error occurred while deleting files: ' . $e->getMessage()); + Log::info('An error occurred while deleting files: ' . $e->getMessage()); } } $this->info('- User "'.$user->username.'" deleted.'); From 437ddc01b4366585b71b0ac08006cb53e9e579c9 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Tue, 30 Jul 2024 16:26:24 -0500 Subject: [PATCH 62/71] removed extraneous `$request->validate()` arguments --- app/Http/Controllers/Auth/ResetPasswordController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index fe1b33128..f1cfbc853 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -87,7 +87,7 @@ class ResetPasswordController extends Controller 'password.not_in' => trans('validation.disallow_same_pwd_as_user_fields'), ]; - $request->validate($this->rules(), $request->all(), $this->validationErrorMessages()); + $request->validate($this->rules()); Log::debug('Checking if '.$request->input('username').' exists'); // Check to see if the user even exists - we'll treat the response the same to prevent user sniffing From 935d2ce29a89b253c40e006cc688ab837701cd1a Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Tue, 30 Jul 2024 15:05:09 -0700 Subject: [PATCH 63/71] fixes admin box alignment --- resources/assets/less/overrides.less | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/assets/less/overrides.less b/resources/assets/less/overrides.less index 12bce00bb..8ef34bb3e 100644 --- a/resources/assets/less/overrides.less +++ b/resources/assets/less/overrides.less @@ -714,6 +714,11 @@ th.css-location > .th-inner::before { margin-top:50px } } +@media screen and (max-width: 1318px) and (min-width: 1200px){ + .box{ + height:170px; + } +} .ellipsis { overflow: hidden; From fccfce2ae8bfd3618a02658a1326ed8a36bf81e9 Mon Sep 17 00:00:00 2001 From: akemidx Date: Tue, 30 Jul 2024 19:27:37 -0400 Subject: [PATCH 64/71] first thought --- resources/views/account/accept/create.blade.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/resources/views/account/accept/create.blade.php b/resources/views/account/accept/create.blade.php index b9843cd47..e22798505 100644 --- a/resources/views/account/accept/create.blade.php +++ b/resources/views/account/accept/create.blade.php @@ -134,11 +134,13 @@ }); $('#submit-button').on("click", function (event) { - if (signaturePad.isEmpty()) { - alert("Please provide signature first."); - return false; - } else { - $('#signature_output').val(signaturePad.toDataURL()); + if(signaturePad != null) { + if (signaturePad.isEmpty()) { + alert("Please provide signature first."); + return false; + } else { + $('#signature_output').val(signaturePad.toDataURL()); + } } }); From 8d1fa362f737adbcb05d64785c106ea76b775237 Mon Sep 17 00:00:00 2001 From: akemidx Date: Wed, 31 Jul 2024 07:13:42 -0400 Subject: [PATCH 65/71] restoring code --- resources/views/account/accept/create.blade.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/resources/views/account/accept/create.blade.php b/resources/views/account/accept/create.blade.php index e22798505..4dc5d5cd6 100644 --- a/resources/views/account/accept/create.blade.php +++ b/resources/views/account/accept/create.blade.php @@ -134,15 +134,11 @@ }); $('#submit-button').on("click", function (event) { - if(signaturePad != null) { - if (signaturePad.isEmpty()) { - alert("Please provide signature first."); - return false; - } else { - $('#signature_output').val(signaturePad.toDataURL()); - } - } - }); + if (signaturePad.isEmpty()) { + alert("Please provide signature first."); + return false; + } else { + $('#signature_output').val(signaturePad.toDataURL()); From b60e22bcb4da19bb7948a3aaf609ab7c3801634a Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Wed, 31 Jul 2024 11:10:33 -0700 Subject: [PATCH 66/71] adds closing brackets to signature pad --- resources/views/account/accept/create.blade.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/views/account/accept/create.blade.php b/resources/views/account/accept/create.blade.php index 4dc5d5cd6..b9843cd47 100644 --- a/resources/views/account/accept/create.blade.php +++ b/resources/views/account/accept/create.blade.php @@ -139,6 +139,8 @@ return false; } else { $('#signature_output').val(signaturePad.toDataURL()); + } + }); From f44abd0b282b87b1385f2516f1b9aebde065ca3a Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 31 Jul 2024 21:43:09 +0100 Subject: [PATCH 67/71] Fixed button label Signed-off-by: snipe --- resources/views/hardware/checkin.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/hardware/checkin.blade.php b/resources/views/hardware/checkin.blade.php index 1efd39427..efd050266 100755 --- a/resources/views/hardware/checkin.blade.php +++ b/resources/views/hardware/checkin.blade.php @@ -129,7 +129,7 @@ + @if ($asset->asset_tag) +
+
+ {{ trans('admin/hardware/form.tag') }} +
+
+ {{ $asset->asset_tag }} + + +
+
+ @endif + @if ($asset->deleted_at!='')
From b804791ff64409f8e966e0741b39848ad9d641a8 Mon Sep 17 00:00:00 2001 From: Florent Bervas Date: Mon, 5 Aug 2024 12:26:29 +0000 Subject: [PATCH 70/71] feature: extend search capabilities to other assets attributes --- app/Http/Controllers/Assets/AssetsController.php | 9 +++++++-- resources/views/hardware/index.blade.php | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index 0852a4624..24f39070d 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -478,9 +478,14 @@ class AssetsController extends Controller $tag = $tag ? $tag : $request->get('assetTag'); $topsearch = ($request->get('topsearch') == 'true'); - if (! $asset = Asset::where('asset_tag', '=', $tag)->first()) { - return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist')); + // Search for an exact and unique asset tag match + $assets = Asset::where('asset_tag', '=', $tag); + + // If not a unique result, redirect to the index view + if ($assets->count() != 1) { + return redirect()->route('hardware.index')->with('search', $tag); } + $asset = $assets->first(); $this->authorize('view', $asset); return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch); diff --git a/resources/views/hardware/index.blade.php b/resources/views/hardware/index.blade.php index d30a1c012..85a82bd40 100755 --- a/resources/views/hardware/index.blade.php +++ b/resources/views/hardware/index.blade.php @@ -73,6 +73,7 @@ data-pagination="true" data-id-table="assetsListingTable" data-search="true" + data-search-text="{{ e(Session::get('search')) }}" data-side-pagination="server" data-show-columns="true" data-show-export="true" From ad794248fe3c66172f41696665f2e776bd9503b4 Mon Sep 17 00:00:00 2001 From: Florent Bervas Date: Mon, 5 Aug 2024 13:44:26 +0000 Subject: [PATCH 71/71] add a warning message if asset tag not found --- app/Http/Controllers/Assets/AssetsController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index 24f39070d..2430cd00f 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -483,7 +483,9 @@ class AssetsController extends Controller // If not a unique result, redirect to the index view if ($assets->count() != 1) { - return redirect()->route('hardware.index')->with('search', $tag); + return redirect()->route('hardware.index') + ->with('search', $tag) + ->with('warning', trans('admin/hardware/message.does_not_exist_var', [ 'asset_tag' => $tag ])); } $asset = $assets->first(); $this->authorize('view', $asset);
{{ trans('general.user') }}{{ trans('general.checked_out_to') }} {{ trans('general.notes') }} {{ trans('admin/hardware/table.checkout_date') }} {{ trans('table.actions') }}