From 8e8b1068ff917e03ead39bdb121db07631b22b98 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Mon, 27 Nov 2023 14:50:43 +0000 Subject: [PATCH 01/53] Beginnings of LDAP test suite --- composer.json | 1 + composer.lock | 209 ++++++++++++++++++++++++++++++++++++- tests/Support/Settings.php | 12 +++ tests/Unit/LdapTest.php | 28 +++++ 4 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 tests/Unit/LdapTest.php diff --git a/composer.json b/composer.json index 020b2f9ca7..58c2b6bedc 100644 --- a/composer.json +++ b/composer.json @@ -80,6 +80,7 @@ "mockery/mockery": "^1.4", "nunomaduro/larastan": "^1.0", "nunomaduro/phpinsights": "^2.7", + "php-mock/php-mock-phpunit": "^2.8", "phpunit/php-token-stream": "^3.1", "phpunit/phpunit": "^9.0", "squizlabs/php_codesniffer": "^3.5", diff --git a/composer.lock b/composer.lock index 7ca88da10f..b1fef91963 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "348f96db24a0f8dfb595ee38b38b34eb", + "content-hash": "f4f3b6b02d044ed3e54cdd509b01c3dc", "packages": [ { "name": "alek13/slack", @@ -14100,6 +14100,213 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "php-mock/php-mock", + "version": "2.4.1", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock.git", + "reference": "6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock/zipball/6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d", + "reference": "6240b6f0a76d7b9d1ee4d70e686a7cc711619a9d", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0", + "phpunit/php-text-template": "^1 || ^2 || ^3" + }, + "replace": { + "malkusch/php-mock": "*" + }, + "require-dev": { + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.0 || ^9.0 || ^10.0", + "squizlabs/php_codesniffer": "^3.5" + }, + "suggest": { + "php-mock/php-mock-phpunit": "Allows integration into PHPUnit testcase with the trait PHPMock." + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "phpmock\\": [ + "classes/", + "tests/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "PHP-Mock can mock built-in PHP functions (e.g. time()). PHP-Mock relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "issues": "https://github.com/php-mock/php-mock/issues", + "source": "https://github.com/php-mock/php-mock/tree/2.4.1" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2023-06-12T20:48:52+00:00" + }, + { + "name": "php-mock/php-mock-integration", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-integration.git", + "reference": "04f4a8d5442ca457b102b5204673f77323e3edb5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-integration/zipball/04f4a8d5442ca457b102b5204673f77323e3edb5", + "reference": "04f4a8d5442ca457b102b5204673f77323e3edb5", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "php-mock/php-mock": "^2.4", + "phpunit/php-text-template": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.27 || ^6 || ^7 || ^8 || ^9 || ^10" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\integration\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Integration package for PHP-Mock", + "homepage": "https://github.com/php-mock/php-mock-integration", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double" + ], + "support": { + "issues": "https://github.com/php-mock/php-mock-integration/issues", + "source": "https://github.com/php-mock/php-mock-integration/tree/2.2.1" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2023-02-13T09:51:29+00:00" + }, + { + "name": "php-mock/php-mock-phpunit", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-phpunit.git", + "reference": "56edee85ad3232caa0202f98f2a3c899ab16bdb7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-phpunit/zipball/56edee85ad3232caa0202f98f2a3c899ab16bdb7", + "reference": "56edee85ad3232caa0202f98f2a3c899ab16bdb7", + "shasum": "" + }, + "require": { + "php": ">=7", + "php-mock/php-mock-integration": "^2.2.1", + "phpunit/phpunit": "^6 || ^7 || ^8 || ^9 || ^10.0.17" + }, + "require-dev": { + "mockery/mockery": "^1.3.6" + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ], + "psr-4": { + "phpmock\\phpunit\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Mock built-in PHP functions (e.g. time()) with PHPUnit. This package relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock-phpunit", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "phpunit", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "issues": "https://github.com/php-mock/php-mock-phpunit/issues", + "source": "https://github.com/php-mock/php-mock-phpunit/tree/2.8.0" + }, + "funding": [ + { + "url": "https://github.com/michalbundyra", + "type": "github" + } + ], + "time": "2023-10-30T07:06:12+00:00" + }, { "name": "php-parallel-lint/php-parallel-lint", "version": "v1.3.2", diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php index 17f8af23d2..0ca05a4752 100644 --- a/tests/Support/Settings.php +++ b/tests/Support/Settings.php @@ -3,6 +3,7 @@ namespace Tests\Support; use App\Models\Setting; +use Illuminate\Support\Facades\Crypt; class Settings { @@ -67,6 +68,17 @@ class Settings } + public function enableLdap(): Settings + { + return $this->update([ + 'ldap_enabled' => 1, + 'ldap_server' => 'ldaps://ldap.example.com', + 'ldap_uname' => 'fake_username', + 'ldap_pword' => Crypt::encrypt("fake_password"), + 'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com' + ]); + } + /** * @param array $attributes Attributes to modify in the application's settings. */ diff --git a/tests/Unit/LdapTest.php b/tests/Unit/LdapTest.php new file mode 100644 index 0000000000..7b94f1aac5 --- /dev/null +++ b/tests/Unit/LdapTest.php @@ -0,0 +1,28 @@ +settings->enableLdap(); + + $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect"); + $ldap_connect->expects($this->once())->willReturn('hello'); + + $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); + $ldap_set_option->expects($this->exactly(3)); + + + $blah = Ldap::connectToLdap(); + $this->assertEquals('hello',$blah,"LDAP_connect should return 'hello'"); + } +} From 45e9d0597a3d2d928bf349c84f0a880bf88592da Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Mon, 27 Nov 2023 11:36:47 -0800 Subject: [PATCH 02/53] makes user total asset cost appear conditionally --- resources/views/users/view.blade.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php index ea5e8d80df..4e9376f092 100755 --- a/resources/views/users/view.blade.php +++ b/resources/views/users/view.blade.php @@ -645,6 +645,7 @@ + @endif From c997ae44c2750e2e22faa98d84e78e7b9e7349a8 Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 20 Nov 2023 22:56:59 +0000 Subject: [PATCH 03/53] FAFO troubleshooting Signed-off-by: snipe --- .../Assets/BulkAssetsController.php | 110 ++++++++++-------- resources/views/hardware/bulk.blade.php | 7 +- 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index 45ca5bab7c..df7c72ed09 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -23,6 +23,13 @@ class BulkAssetsController extends Controller /** * Display the bulk edit page. * + * This method is super weird because it's kinda of like a controller within a controller. + * It's main function is to determine what the bulk action in, and then return a view with + * the information that view needs, be it bulk delete, bulk edit, restore, etc. + * + * This is something that made sense at the time, but sort of doesn't make sense now. A JS front-end to determine form + * action would make a lot more sense here and make things a lot more clear. + * * @author [A. Gianotto] [] * @return View * @internal param int $assetId @@ -32,7 +39,9 @@ class BulkAssetsController extends Controller public function edit(Request $request) { $this->authorize('view', Asset::class); - + + \Log::debug('Bulk action was triggered: '.$request->input('bulk_actions')); + if (! $request->filled('ids')) { return redirect()->back()->with('error', trans('admin/hardware/message.update.no_assets_selected')); } @@ -41,60 +50,45 @@ class BulkAssetsController extends Controller $bulk_back_url = request()->headers->get('referer'); session(['bulk_back_url' => $bulk_back_url]); - $asset_ids = array_values(array_unique($request->input('ids'))); - - //custom fields logic - $asset_custom_field = Asset::with(['model.fieldset.fields', 'model'])->whereIn('id', $asset_ids)->whereHas('model', function ($query) { - return $query->where('fieldset_id', '!=', null); - })->get(); - - $models = $asset_custom_field->unique('model_id'); - $modelNames = []; - foreach($models as $model) { - $modelNames[] = $model->model->name; - } + $asset_ids = $request->input('ids'); + $assets = Asset::with('assignedTo', 'location', 'model')->find($asset_ids); if ($request->filled('bulk_actions')) { + + switch ($request->input('bulk_actions')) { case 'labels': $this->authorize('view', Asset::class); - $assets_found = Asset::find($asset_ids); - - if ($assets_found->isEmpty()){ - return redirect()->back(); - } return (new Label) - ->with('assets', $assets_found) + ->with('assets', $assets) ->with('settings', Setting::getSettings()) ->with('bulkedit', true) ->with('count', 0); case 'delete': $this->authorize('delete', Asset::class); - $assets = Asset::with('assignedTo', 'location')->find($asset_ids); - $assets->each(function ($asset) { - $this->authorize('delete', $asset); + $assets->each(function ($assets) { + $this->authorize('delete', $assets); }); return view('hardware/bulk-delete')->with('assets', $assets); case 'restore': + \Log::debug('We seem to be bulk restoring'); $this->authorize('update', Asset::class); - $assets = Asset::withTrashed()->find($asset_ids); $assets->each(function ($asset) { $this->authorize('delete', $asset); }); - return view('hardware/bulk-restore')->with('assets', $assets); case 'edit': $this->authorize('update', Asset::class); + \Log::debug('We seem to be bulk editing'); + return view('hardware/bulk') - ->with('assets', $asset_ids) - ->with('statuslabel_list', Helper::statusLabelList()) - ->with('models', $models->pluck(['model'])) - ->with('modelNames', $modelNames); + ->with('assets', $assets) + ->with('statuslabel_list', Helper::statusLabelList()); } } @@ -115,27 +109,35 @@ class BulkAssetsController extends Controller $has_errors = 0; $error_array = array(); + + print_r($assets, true); // Get the back url from the session and then destroy the session $bulk_back_url = route('hardware.index'); + if ($request->session()->has('bulk_back_url')) { $bulk_back_url = $request->session()->pull('bulk_back_url'); } $custom_field_columns = CustomField::all()->pluck('db_column')->toArray(); + + \Log::debug('Custom fields columns: '); + \Log::debug(print_r($custom_field_columns, true)); - if (Session::exists('ids')) { - $assets = Session::get('ids'); - } elseif (! $request->filled('ids') || count($request->input('ids')) <= 0) { + if (! $request->filled('ids') || count($request->input('ids')) == 0) { return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected')); } - - $assets = array_keys($request->input('ids')); - - if ($request->anyFilled($custom_field_columns)) { + + // $assetsIds = array_keys($request->input('ids')); + $assets = Asset::find($request->input('ids')); + + // We should tighten checks here - burpsuite could punch through this I'd pull the custom fields for new and old here + if ($request->anyFilled($custom_field_columns)) { $custom_fields_present = true; } else { $custom_fields_present = false; } + + // If ANY of these are filled, prepare to update the values on the assets if (($request->filled('purchase_date')) || ($request->filled('expected_checkin')) || ($request->filled('purchase_cost')) @@ -154,7 +156,8 @@ class BulkAssetsController extends Controller || ($request->anyFilled($custom_field_columns)) ) { - foreach ($assets as $assetId) { + // Let's loop through those assets and build an update array + foreach ($assets as $asset) { $this->update_array = []; @@ -186,7 +189,6 @@ class BulkAssetsController extends Controller $this->update_array['purchase_cost'] = $request->input('purchase_cost'); } - if ($request->filled('company_id')) { $this->update_array['company_id'] = $request->input('company_id'); if ($request->input('company_id') == 'clear') { @@ -195,20 +197,23 @@ class BulkAssetsController extends Controller } if ($request->filled('rtd_location_id')) { + if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '0')) { $this->update_array['rtd_location_id'] = $request->input('rtd_location_id'); } + if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '1')) { $this->update_array['location_id'] = $request->input('rtd_location_id'); $this->update_array['rtd_location_id'] = $request->input('rtd_location_id'); } + if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '2')) { $this->update_array['location_id'] = $request->input('rtd_location_id'); } + } $changed = []; - $asset = Asset::find($assetId); foreach ($this->update_array as $key => $value) { if ($this->update_array[$key] != $asset->{$key}) { @@ -216,20 +221,25 @@ class BulkAssetsController extends Controller $changed[$key]['new'] = $this->update_array[$key]; } } - + + \Log::debug(print_r($changed, true)); + + $existing_assetmodel = $asset->model; + $updated_model = $request->input('model_id'); + + // Use the rules of the new model fieldsets if the model changed + if (($request->filled('model_id')) && ($request->filled('model_id')!=$existing_assetmodel->id)) { + \Log::debug('Old and new models are different - change from '.$asset->model->id.' to model '.$request->input('model_id')); + $this->update_array['model_id'] = $request->input('model_id'); + $updated_model = \App\Models\AssetModel::find($request->input('model_id')); + } + + + /** Start all the custom fields shenanigans */ if ($custom_fields_present) { - $model = $asset->model()->first(); - - // Use the rules of the new model fieldsets if the model changed - if ($request->filled('model_id')) { - $this->update_array['model_id'] = $request->input('model_id'); - $model = \App\Models\AssetModel::find($request->input('model_id')); - } - - // Make sure this model is valid - $assetCustomFields = ($model) ? $model->fieldset : null; + $assetCustomFields = ($updated_model) ? $updated_model->fieldset : null; if ($assetCustomFields && $assetCustomFields->fields) { @@ -260,7 +270,6 @@ class BulkAssetsController extends Controller */ } else { - if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) { // Check if this is an array, and if so, flatten it @@ -278,6 +287,7 @@ class BulkAssetsController extends Controller + \Log::debug(print_r($this->update_array, true)); // Check if it passes validation, and then try to save if (!$asset->update($this->update_array)) { diff --git a/resources/views/hardware/bulk.blade.php b/resources/views/hardware/bulk.blade.php index a7e52dfa56..78db17afc1 100755 --- a/resources/views/hardware/bulk.blade.php +++ b/resources/views/hardware/bulk.blade.php @@ -19,11 +19,10 @@

{{ trans('admin/hardware/form.bulk_update_help') }}

+ +
{{ trans_choice('admin/hardware/form.bulk_update_warn', count($assets), ['asset_count' => count($assets)]) }} - @if (count($models) > 0) - {{ trans_choice('admin/hardware/form.bulk_update_with_custom_field', count($models), ['asset_model_count' => count($models)]) }} - @endif
@@ -189,7 +188,7 @@ - @include("models/custom_fields_form_bulk_edit",["models" => $models]) + @foreach ($assets as $key => $value) From 5574218966389542a0f0870a75505c1a1fc3b3bd Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 21 Nov 2023 00:14:14 +0000 Subject: [PATCH 04/53] More FAFO - cleanup needed, but model_id works now Signed-off-by: snipe --- .../Assets/BulkAssetsController.php | 57 +++++++++++++------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index df7c72ed09..5111b623cf 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -87,7 +87,7 @@ class BulkAssetsController extends Controller \Log::debug('We seem to be bulk editing'); return view('hardware/bulk') - ->with('assets', $assets) + ->with('assets', $asset_ids) ->with('statuslabel_list', Helper::statusLabelList()); } } @@ -109,8 +109,6 @@ class BulkAssetsController extends Controller $has_errors = 0; $error_array = array(); - - print_r($assets, true); // Get the back url from the session and then destroy the session $bulk_back_url = route('hardware.index'); @@ -120,15 +118,24 @@ class BulkAssetsController extends Controller $custom_field_columns = CustomField::all()->pluck('db_column')->toArray(); - \Log::debug('Custom fields columns: '); - \Log::debug(print_r($custom_field_columns, true)); +// \Log::debug('ALL Custom fields columns - these may or may not apply: '); +// \Log::debug(print_r($custom_field_columns, true)); if (! $request->filled('ids') || count($request->input('ids')) == 0) { return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected')); } // $assetsIds = array_keys($request->input('ids')); - $assets = Asset::find($request->input('ids')); + \Log::debug('Request IDs:'); + \Log::debug(print_r(array_keys($request->input('ids')), true)); + + $assets = Asset::whereIn('id', array_keys($request->input('ids')))->get(); + + \Log::debug('Affected asset list: '); + foreach ($assets as $log_asset) { + \Log::debug(' - Asset affected: '.$log_asset->asset_tag); + } + // We should tighten checks here - burpsuite could punch through this I'd pull the custom fields for new and old here if ($request->anyFilled($custom_field_columns)) { @@ -161,18 +168,22 @@ class BulkAssetsController extends Controller $this->update_array = []; + // Leave out model_id and sttaus here because we do math on that later. We have to d some extra + // validation and checks on those two $this->conditionallyAddItem('purchase_date') ->conditionallyAddItem('expected_checkin') ->conditionallyAddItem('order_number') ->conditionallyAddItem('requestable') - ->conditionallyAddItem('status_id') ->conditionallyAddItem('supplier_id') ->conditionallyAddItem('warranty_months') ->conditionallyAddItem('next_audit_date'); foreach ($custom_field_columns as $key => $custom_field_column) { $this->conditionallyAddItem($custom_field_column); - } + } + /** + * Blank out fields that were requested to be blanked out via checkbox + */ if ($request->input('null_purchase_date')=='1') { $this->update_array['purchase_date'] = null; } @@ -213,6 +224,27 @@ class BulkAssetsController extends Controller } + $existing_assetmodel = $asset->model; + + + // Use the new model_id and add it to the existing $this + if (($request->filled('model_id')) && ($request->input('model_id')!= $existing_assetmodel->id)) { + \Log::debug('Old and new models are different - change from '.$asset->model->id.' to model '.$request->input('model_id')); + $this->update_array['model_id'] = $request->input('model_id'); + $updated_model = \App\Models\AssetModel::find($request->input('model_id')); + } + + $existing_status = $asset->statuslabel; + + // Use the new status_id and add it to the existing $this + if (($request->filled('status_id')) && ($request->input('status_id')!= $existing_status->id)) { + \Log::debug('Old and new models are different - change from '.$asset->statuslabel->id.' to model '.$request->input('status_id')); + $this->update_array['status_id'] = $request->input('status_id'); + $updated_status = \App\Models\Statuslabel::find($request->input('status_id')); + } + + + // Anything that happens past this WILL NOT BE logged in the edit log $changed = []; foreach ($this->update_array as $key => $value) { @@ -222,17 +254,10 @@ class BulkAssetsController extends Controller } } + \Log::debug('What changed?'); \Log::debug(print_r($changed, true)); - $existing_assetmodel = $asset->model; - $updated_model = $request->input('model_id'); - // Use the rules of the new model fieldsets if the model changed - if (($request->filled('model_id')) && ($request->filled('model_id')!=$existing_assetmodel->id)) { - \Log::debug('Old and new models are different - change from '.$asset->model->id.' to model '.$request->input('model_id')); - $this->update_array['model_id'] = $request->input('model_id'); - $updated_model = \App\Models\AssetModel::find($request->input('model_id')); - } /** Start all the custom fields shenanigans */ From f9d5c451bca303675e205afad763b3e4e3ea5f91 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 21 Nov 2023 10:28:33 +0000 Subject: [PATCH 05/53] Committing this for now - not done Signed-off-by: snipe --- .../Assets/BulkAssetsController.php | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index 5111b623cf..b02b2e265a 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -7,6 +7,8 @@ use App\Helpers\Helper; use App\Http\Controllers\CheckInOutRequest; use App\Http\Controllers\Controller; use App\Models\Asset; +use App\Models\AssetModel; +use App\Models\Statuslabel; use App\Models\Setting; use App\View\Label; use Illuminate\Http\Request; @@ -174,6 +176,8 @@ class BulkAssetsController extends Controller ->conditionallyAddItem('expected_checkin') ->conditionallyAddItem('order_number') ->conditionallyAddItem('requestable') + ->conditionallyAddItem('model_id') + ->conditionallyAddItem('status_id') ->conditionallyAddItem('supplier_id') ->conditionallyAddItem('warranty_months') ->conditionallyAddItem('next_audit_date'); @@ -224,25 +228,6 @@ class BulkAssetsController extends Controller } - $existing_assetmodel = $asset->model; - - - // Use the new model_id and add it to the existing $this - if (($request->filled('model_id')) && ($request->input('model_id')!= $existing_assetmodel->id)) { - \Log::debug('Old and new models are different - change from '.$asset->model->id.' to model '.$request->input('model_id')); - $this->update_array['model_id'] = $request->input('model_id'); - $updated_model = \App\Models\AssetModel::find($request->input('model_id')); - } - - $existing_status = $asset->statuslabel; - - // Use the new status_id and add it to the existing $this - if (($request->filled('status_id')) && ($request->input('status_id')!= $existing_status->id)) { - \Log::debug('Old and new models are different - change from '.$asset->statuslabel->id.' to model '.$request->input('status_id')); - $this->update_array['status_id'] = $request->input('status_id'); - $updated_status = \App\Models\Statuslabel::find($request->input('status_id')); - } - // Anything that happens past this WILL NOT BE logged in the edit log $changed = []; @@ -256,15 +241,14 @@ class BulkAssetsController extends Controller \Log::debug('What changed?'); \Log::debug(print_r($changed, true)); - - - + /** Start all the custom fields shenanigans */ if ($custom_fields_present) { // Make sure this model is valid - $assetCustomFields = ($updated_model) ? $updated_model->fieldset : null; + // ALISON - FIX THIS BEFORE PUSHING + $assetCustomFields = ($request->input('model_id')) ? $request->input('model_id')->fieldset : null; if ($assetCustomFields && $assetCustomFields->fields) { From 4723cfd4ba7bbfb2c2d29207b94d49a7c2cd854f Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 13:32:47 +0000 Subject: [PATCH 06/53] More refactoring Signed-off-by: snipe --- .../Assets/BulkAssetsController.php | 166 ++++++++++++------ app/Models/Asset.php | 29 ++- resources/views/hardware/bulk.blade.php | 10 +- 3 files changed, 143 insertions(+), 62 deletions(-) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index b02b2e265a..6eca157b71 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -120,8 +120,8 @@ class BulkAssetsController extends Controller $custom_field_columns = CustomField::all()->pluck('db_column')->toArray(); -// \Log::debug('ALL Custom fields columns - these may or may not apply: '); -// \Log::debug(print_r($custom_field_columns, true)); + \Log::debug('ALL Custom fields columns - these may or may not apply: '); + \Log::debug(print_r($custom_field_columns, true)); if (! $request->filled('ids') || count($request->input('ids')) == 0) { return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected')); @@ -139,14 +139,14 @@ class BulkAssetsController extends Controller } - // We should tighten checks here - burpsuite could punch through this I'd pull the custom fields for new and old here - if ($request->anyFilled($custom_field_columns)) { - $custom_fields_present = true; - } else { - $custom_fields_present = false; - } + /** + * If ANY of these are filled, prepare to update the values on the assets. + * + * Additional checks will be needed for some of them to make sure the values + * make sense (for example, changing the status ID to something incompatible with + * its checkout status. + */ - // If ANY of these are filled, prepare to update the values on the assets if (($request->filled('purchase_date')) || ($request->filled('expected_checkin')) || ($request->filled('purchase_cost')) @@ -170,14 +170,17 @@ class BulkAssetsController extends Controller $this->update_array = []; - // Leave out model_id and sttaus here because we do math on that later. We have to d some extra - // validation and checks on those two + /** + * Leave out model_id and status here because we do math on that later. We have to do some extra + * validation and checks on those two. + * + * It's tempting to make these match the request check above, but some of these values require + * extra work to make sure the data makes sense. + */ $this->conditionallyAddItem('purchase_date') ->conditionallyAddItem('expected_checkin') ->conditionallyAddItem('order_number') ->conditionallyAddItem('requestable') - ->conditionallyAddItem('model_id') - ->conditionallyAddItem('status_id') ->conditionallyAddItem('supplier_id') ->conditionallyAddItem('warranty_months') ->conditionallyAddItem('next_audit_date'); @@ -211,6 +214,53 @@ class BulkAssetsController extends Controller } } + /** + * We're trying to change the model ID - we need to do some extra checks here to make sure + * the custom field values work for the custom fieldset rules around this asset. Uniqueness + * and requiredness across the fieldset is particularly important, since those are + * fieldset-specific attributes. + */ + if ($request->filled('model_id')) { + \Log::debug('Change the model ID!'); + $asset->model_id = Model::find($request->input('model_id'))->id; + \Log::debug('New model ID is:'.$asset->model_id); + } + + /** + * We're trying to change the status ID - we need to do some extra checks here to + * make sure the status label type is one that makes sense for the state of the asset, + * for example, we shouldn't be able to make an asset archived if it's currently assigned + * to someone/something. + */ + if ($request->filled('status_id')) { + \Log::debug('Change the status ID!'); + $updated_status = Statuslabel::find($request->input('status_id')); + \Log::debug('New status ID is:'.$updated_status->id); + \Log::debug('Status label type is: '.$updated_status->getStatuslabelType()); + + // We cannot assign a non-deployable status type if the asset is already assigned. + // This could probably be added to a form request. + // If the asset isn't assigned, we don't care what the status is. + // Otherwise we need to make sure the status type is still a deployable one. + if ( + ($asset->assigned_to == '') + || ($updated_status->deployable == '1') && ($asset->assetstatus->deployable == '1') + ) { + $asset->status_id = $updated_status->id; + } + + } + + /** + * We're changing the location ID - figure out which location we should apply + * this change to: + * + * 0 - RTD location only + * 1 - location ID and RTD location ID + * 2 - location ID only + * + * Note: this is kinda dumb and we should just use human-readable values IMHO. - snipe + */ if ($request->filled('rtd_location_id')) { if (($request->filled('update_real_loc')) && (($request->input('update_real_loc')) == '0')) { @@ -229,70 +279,74 @@ class BulkAssetsController extends Controller } - // Anything that happens past this WILL NOT BE logged in the edit log + /** + * ------------------------------------------------------------------------------ + * ANYTHING that happens past this foreach + * WILL NOT BE logged in the edit log_meta data + * ------------------------------------------------------------------------------ + */ $changed = []; foreach ($this->update_array as $key => $value) { + if ($this->update_array[$key] != $asset->{$key}) { $changed[$key]['old'] = $asset->{$key}; $changed[$key]['new'] = $this->update_array[$key]; } + } \Log::debug('What changed?'); \Log::debug(print_r($changed, true)); - /** Start all the custom fields shenanigans */ - if ($custom_fields_present) { + /** + * Start all the custom fields shenanigans + */ - // Make sure this model is valid - // ALISON - FIX THIS BEFORE PUSHING - $assetCustomFields = ($request->input('model_id')) ? $request->input('model_id')->fieldset : null; + // Does the model have a fieldset? + if ($asset->model->fieldset) { + foreach ($asset->model->fieldset->fields as $field) { - if ($assetCustomFields && $assetCustomFields->fields) { - - foreach ($assetCustomFields->fields as $field) { - - if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted=='1')) { - $decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column}); - - /* - * Check if the decrypted existing value is different from one we just submitted - * and if not, pull it out of the object since it shouldn't really be updating at all. - * If we don't do this, it will try to re-encrypt it, and the same value encrypted two - * different times will have different values, so it will *look* like it was updated - * but it wasn't. - */ - if ($decrypted_old != $this->update_array[$field->db_column]) { - $asset->{$field->db_column} = \Crypt::encrypt($this->update_array[$field->db_column]); - } else { - /* - * Remove the encrypted custom field from the update_array, since nothing changed - */ - unset($this->update_array[$field->db_column]); - unset($asset->{$field->db_column}); - } + if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) { + $decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column}); + /* + * Check if the decrypted existing value is different from one we just submitted + * and if not, pull it out of the object since it shouldn't really be updating at all. + * If we don't do this, it will try to re-encrypt it, and the same value encrypted two + * different times will have different values, so it will *look* like it was updated + * but it wasn't. + */ + if ($decrypted_old != $this->update_array[$field->db_column]) { + $asset->{$field->db_column} = \Crypt::encrypt($this->update_array[$field->db_column]); + } else { /* - * These custom fields aren't encrypted, just carry on as usual + * Remove the encrypted custom field from the update_array, since nothing changed */ + unset($this->update_array[$field->db_column]); + unset($asset->{$field->db_column}); + } + + /* + * These custom fields aren't encrypted, just carry on as usual + */ + } else { + + if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) { + + // Check if this is an array, and if so, flatten it + if (is_array($this->update_array[$field->db_column])) { + $asset->{$field->db_column} = implode(', ', $this->update_array[$field->db_column]); } else { - - if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) { - - // Check if this is an array, and if so, flatten it - if (is_array($this->update_array[$field->db_column])) { - $asset->{$field->db_column} = implode(', ', $this->update_array[$field->db_column]); - } else { - $asset->{$field->db_column} = $this->update_array[$field->db_column]; - } - } + $asset->{$field->db_column} = $this->update_array[$field->db_column]; } + } + } + + } // endforeach + } - } // endforeach - } // end custom field check - } // end custom fields handler diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 4e5a25974e..7ef526d891 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -266,7 +266,7 @@ class Asset extends Depreciable /** * Determines if an asset is available for checkout. - * This checks to see if the it's checked out to an invalid (deleted) user + * This checks to see if it's checked out to an invalid (deleted) user * OR if the assigned_to and deleted_at fields on the asset are empty AND * that the status is deployable * @@ -292,6 +292,31 @@ class Asset extends Depreciable } + /** + * Determines if an asset is available for checkout. + * This checks to see if it's checked out to an invalid (deleted) user + * OR if the assigned_to and deleted_at fields on the asset are empty AND + * that the status is deployable + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return bool + */ + public function isDeployableMeta() + { + + // The asset status is not archived and is deployable + if (($this->assetstatus) && ($this->assetstatus->archived == '0') && (! $this->deleted_at) + && ($this->assetstatus->deployable == '1')) + { + return true; + + } + + return false; + } + + /** * Checks the asset out to the target * @@ -753,7 +778,7 @@ class Asset extends Depreciable } /** - * Establishes the asset -> status relationship + * Establishes the asset -> license seats relationship * * @author [A. Gianotto] [] * @since [v4.0] diff --git a/resources/views/hardware/bulk.blade.php b/resources/views/hardware/bulk.blade.php index 78db17afc1..0b0c6876e4 100755 --- a/resources/views/hardware/bulk.blade.php +++ b/resources/views/hardware/bulk.blade.php @@ -21,15 +21,16 @@ -
- {{ trans_choice('admin/hardware/form.bulk_update_warn', count($assets), ['asset_count' => count($assets)]) }} -
- {{ csrf_field() }}
+ +
+ {{ trans_choice('admin/hardware/form.bulk_update_warn', count($assets), ['asset_count' => count($assets)]) }} +
+
@@ -75,6 +76,7 @@
{{ Form::select('status_id', $statuslabel_list , old('status_id'), array('class'=>'select2', 'style'=>'width:100%', 'aria-label'=>'status_id')) }} +

If assets are already assigned, they cannot be changed to a non-deployable status type and this value change will be skipped.

{!! $errors->first('status_id', '') !!}
From 9d786d9386df584d4aab96573cad895b2d4ac069 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 13:43:33 +0000 Subject: [PATCH 07/53] Removed unused method Signed-off-by: snipe --- app/Models/Asset.php | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 7ef526d891..f23ff52f64 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -292,31 +292,6 @@ class Asset extends Depreciable } - /** - * Determines if an asset is available for checkout. - * This checks to see if it's checked out to an invalid (deleted) user - * OR if the assigned_to and deleted_at fields on the asset are empty AND - * that the status is deployable - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @return bool - */ - public function isDeployableMeta() - { - - // The asset status is not archived and is deployable - if (($this->assetstatus) && ($this->assetstatus->archived == '0') && (! $this->deleted_at) - && ($this->assetstatus->deployable == '1')) - { - return true; - - } - - return false; - } - - /** * Checks the asset out to the target * From fa1176ce141dfe581396c69dcbb104ebd07cccbc Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 15:14:12 +0000 Subject: [PATCH 08/53] Added translation Signed-off-by: snipe --- resources/lang/en/general.php | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index a568e00436..1f2f4322cc 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -491,5 +491,6 @@ return [ 'upload_error' => 'Error uploading file. Please check that there are no empty rows and that no column names are duplicated.', 'copy_to_clipboard' => 'Copy to Clipboard', 'copied' => 'Copied!', + 'status_compatibility' => 'If assets are already assigned, they cannot be changed to a non-deployable status type and this value change will be skipped.', ]; From c91713e20a5aac52520d94f0564da2e6dfc8419e Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 15:14:55 +0000 Subject: [PATCH 09/53] Removed debugging Signed-off-by: snipe --- .../Assets/BulkAssetsController.php | 29 ++----------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index 6eca157b71..1151337ba7 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -41,9 +41,7 @@ class BulkAssetsController extends Controller public function edit(Request $request) { $this->authorize('view', Asset::class); - - \Log::debug('Bulk action was triggered: '.$request->input('bulk_actions')); - + if (! $request->filled('ids')) { return redirect()->back()->with('error', trans('admin/hardware/message.update.no_assets_selected')); } @@ -77,7 +75,6 @@ class BulkAssetsController extends Controller return view('hardware/bulk-delete')->with('assets', $assets); case 'restore': - \Log::debug('We seem to be bulk restoring'); $this->authorize('update', Asset::class); $assets->each(function ($asset) { $this->authorize('delete', $asset); @@ -86,7 +83,6 @@ class BulkAssetsController extends Controller case 'edit': $this->authorize('update', Asset::class); - \Log::debug('We seem to be bulk editing'); return view('hardware/bulk') ->with('assets', $asset_ids) @@ -120,23 +116,14 @@ class BulkAssetsController extends Controller $custom_field_columns = CustomField::all()->pluck('db_column')->toArray(); - \Log::debug('ALL Custom fields columns - these may or may not apply: '); - \Log::debug(print_r($custom_field_columns, true)); if (! $request->filled('ids') || count($request->input('ids')) == 0) { return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected')); } - // $assetsIds = array_keys($request->input('ids')); - \Log::debug('Request IDs:'); - \Log::debug(print_r(array_keys($request->input('ids')), true)); $assets = Asset::whereIn('id', array_keys($request->input('ids')))->get(); - \Log::debug('Affected asset list: '); - foreach ($assets as $log_asset) { - \Log::debug(' - Asset affected: '.$log_asset->asset_tag); - } /** @@ -221,9 +208,7 @@ class BulkAssetsController extends Controller * fieldset-specific attributes. */ if ($request->filled('model_id')) { - \Log::debug('Change the model ID!'); - $asset->model_id = Model::find($request->input('model_id'))->id; - \Log::debug('New model ID is:'.$asset->model_id); + $asset->model_id = AssetModel::find($request->input('model_id'))->id; } /** @@ -233,10 +218,7 @@ class BulkAssetsController extends Controller * to someone/something. */ if ($request->filled('status_id')) { - \Log::debug('Change the status ID!'); $updated_status = Statuslabel::find($request->input('status_id')); - \Log::debug('New status ID is:'.$updated_status->id); - \Log::debug('Status label type is: '.$updated_status->getStatuslabelType()); // We cannot assign a non-deployable status type if the asset is already assigned. // This could probably be added to a form request. @@ -296,10 +278,6 @@ class BulkAssetsController extends Controller } - \Log::debug('What changed?'); - \Log::debug(print_r($changed, true)); - - /** * Start all the custom fields shenanigans */ @@ -348,9 +326,6 @@ class BulkAssetsController extends Controller } - - - \Log::debug(print_r($this->update_array, true)); // Check if it passes validation, and then try to save if (!$asset->update($this->update_array)) { From 187d3abeb4d5619fe8585d57decf238a1947fe86 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 15:15:07 +0000 Subject: [PATCH 10/53] Use translation string Signed-off-by: snipe --- resources/views/hardware/bulk.blade.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/resources/views/hardware/bulk.blade.php b/resources/views/hardware/bulk.blade.php index 0b0c6876e4..fa4680e2e8 100755 --- a/resources/views/hardware/bulk.blade.php +++ b/resources/views/hardware/bulk.blade.php @@ -29,6 +29,10 @@
{{ trans_choice('admin/hardware/form.bulk_update_warn', count($assets), ['asset_count' => count($assets)]) }} + + @if (count($models) > 0) + {{ trans_choice('admin/hardware/form.bulk_update_with_custom_field', count($models), ['asset_model_count' => count($models)]) }} + @endif
@@ -76,7 +80,7 @@
{{ Form::select('status_id', $statuslabel_list , old('status_id'), array('class'=>'select2', 'style'=>'width:100%', 'aria-label'=>'status_id')) }} -

If assets are already assigned, they cannot be changed to a non-deployable status type and this value change will be skipped.

+

{{ trans('general.status_compatibility') }}

{!! $errors->first('status_id', '') !!}
@@ -190,8 +194,8 @@
+ @include("models/custom_fields_form_bulk_edit",["models" => $models]) - @foreach ($assets as $key => $value) @endforeach From 6ae03a204bc407dac2033692094124cfa8882c39 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 15:21:14 +0000 Subject: [PATCH 11/53] Added the model info back in Signed-off-by: snipe --- .../Controllers/Assets/BulkAssetsController.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index 1151337ba7..60f7b874ae 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -41,7 +41,7 @@ class BulkAssetsController extends Controller public function edit(Request $request) { $this->authorize('view', Asset::class); - + if (! $request->filled('ids')) { return redirect()->back()->with('error', trans('admin/hardware/message.update.no_assets_selected')); } @@ -53,6 +53,17 @@ class BulkAssetsController extends Controller $asset_ids = $request->input('ids'); $assets = Asset::with('assignedTo', 'location', 'model')->find($asset_ids); + //custom fields logic + $asset_custom_field = Asset::with(['model.fieldset.fields', 'model'])->whereIn('id', $asset_ids)->whereHas('model', function ($query) { + return $query->where('fieldset_id', '!=', null); + })->get(); + + $models = $asset_custom_field->unique('model_id'); + $modelNames = []; + foreach($models as $model) { + $modelNames[] = $model->model->name; + } + if ($request->filled('bulk_actions')) { @@ -86,6 +97,8 @@ class BulkAssetsController extends Controller return view('hardware/bulk') ->with('assets', $asset_ids) + ->with('models', $models->pluck(['model'])) + ->with('modelNames', $modelNames) ->with('statuslabel_list', Helper::statusLabelList()); } } From 2c6b957fbe565fa8b116571b5f792227a6db3b4a Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 15:28:37 +0000 Subject: [PATCH 12/53] Removed unused query Signed-off-by: snipe --- app/Http/Controllers/Assets/BulkAssetsController.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index 60f7b874ae..ded29bc735 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -53,12 +53,7 @@ class BulkAssetsController extends Controller $asset_ids = $request->input('ids'); $assets = Asset::with('assignedTo', 'location', 'model')->find($asset_ids); - //custom fields logic - $asset_custom_field = Asset::with(['model.fieldset.fields', 'model'])->whereIn('id', $asset_ids)->whereHas('model', function ($query) { - return $query->where('fieldset_id', '!=', null); - })->get(); - - $models = $asset_custom_field->unique('model_id'); + $models = $assets->unique('model_id'); $modelNames = []; foreach($models as $model) { $modelNames[] = $model->model->name; From 3b9f06962793529b1ffde1beeb33bd66d51cbe89 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 15:54:42 +0000 Subject: [PATCH 13/53] Switched back to old version Signed-off-by: snipe --- app/Http/Controllers/Assets/BulkAssetsController.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index ded29bc735..89ed27e8be 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -42,6 +42,9 @@ class BulkAssetsController extends Controller { $this->authorize('view', Asset::class); + /** + * No asset IDs were passed + */ if (! $request->filled('ids')) { return redirect()->back()->with('error', trans('admin/hardware/message.update.no_assets_selected')); } @@ -50,6 +53,7 @@ class BulkAssetsController extends Controller $bulk_back_url = request()->headers->get('referer'); session(['bulk_back_url' => $bulk_back_url]); + $asset_ids = $request->input('ids'); $assets = Asset::with('assignedTo', 'location', 'model')->find($asset_ids); @@ -92,9 +96,9 @@ class BulkAssetsController extends Controller return view('hardware/bulk') ->with('assets', $asset_ids) + ->with('statuslabel_list', Helper::statusLabelList()) ->with('models', $models->pluck(['model'])) - ->with('modelNames', $modelNames) - ->with('statuslabel_list', Helper::statusLabelList()); + ->with('modelNames', $modelNames); } } From 2d4a14d4bbbeb28a2ef3280ed9a54d2dfe69844a Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 15:55:41 +0000 Subject: [PATCH 14/53] Fixed from rebase :( Signed-off-by: snipe --- app/Http/Controllers/Assets/BulkAssetsController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index 89ed27e8be..dd8b26a193 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -86,6 +86,7 @@ class BulkAssetsController extends Controller case 'restore': $this->authorize('update', Asset::class); + $assets = Asset::withTrashed()->find($asset_ids); $assets->each(function ($asset) { $this->authorize('delete', $asset); }); From 2247be77d83b316a1d954898c2a642a30b369232 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 15:56:20 +0000 Subject: [PATCH 15/53] Fixed translation Signed-off-by: snipe --- resources/views/hardware/bulk-restore.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/hardware/bulk-restore.blade.php b/resources/views/hardware/bulk-restore.blade.php index caabe9fab8..e4bfb6e4dd 100644 --- a/resources/views/hardware/bulk-restore.blade.php +++ b/resources/views/hardware/bulk-restore.blade.php @@ -30,7 +30,7 @@ {{ trans('admin/hardware/table.id') }} - {{ trans('admin/hardware/table.name') }} + {{ trans('admin/hardware/form.name') }} {{ trans('admin/hardware/table.location')}} From 601ebcc1e6f83c92ec525eec58099ed441b0ebff Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 16:00:42 +0000 Subject: [PATCH 16/53] Removed table header contraint Signed-off-by: snipe --- resources/views/hardware/view.blade.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index 5a043ffc40..badb4b1e6b 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -1206,15 +1206,15 @@ {{ trans('admin/hardware/table.icon') }} - {{ trans('general.date') }} - {{ trans('general.admin') }} - {{ trans('general.action') }} - {{ trans('general.item') }} - {{ trans('general.target') }} - {{ trans('general.notes') }} - {{ trans('general.signature') }} - {{ trans('general.download') }} - {{ trans('admin/hardware/table.changed')}} + {{ trans('general.date') }} + {{ trans('general.admin') }} + {{ trans('general.action') }} + {{ trans('general.item') }} + {{ trans('general.target') }} + {{ trans('general.notes') }} + {{ trans('general.signature') }} + {{ trans('general.download') }} + {{ trans('admin/hardware/table.changed')}} From 899890b22422993320bd415c23c6e89a3cf56ff1 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 28 Nov 2023 16:25:35 +0000 Subject: [PATCH 17/53] Use update array nomenclature Signed-off-by: snipe --- app/Http/Controllers/Assets/BulkAssetsController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index dd8b26a193..d0c66d4b11 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -221,7 +221,7 @@ class BulkAssetsController extends Controller * fieldset-specific attributes. */ if ($request->filled('model_id')) { - $asset->model_id = AssetModel::find($request->input('model_id'))->id; + $this->update_array['model_id'] = AssetModel::find($request->input('model_id'))->id; } /** @@ -241,7 +241,7 @@ class BulkAssetsController extends Controller ($asset->assigned_to == '') || ($updated_status->deployable == '1') && ($asset->assetstatus->deployable == '1') ) { - $asset->status_id = $updated_status->id; + $this->update_array['status_id'] = $updated_status->id; } } From 9e59550b7915adf5d64a790d1d3b103ccc8740bb Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Tue, 28 Nov 2023 10:08:32 -0800 Subject: [PATCH 18/53] removes the row instead of just the optional values --- resources/views/users/view.blade.php | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php index 4e9376f092..0ed5c93b80 100755 --- a/resources/views/users/view.blade.php +++ b/resources/views/users/view.blade.php @@ -638,14 +638,14 @@ @endif + @if($user->getUserTotalCost()->total_user_cost > 0)
- - + + @endif - - - From 108658520d7afc8037165e905867f1e932475702 Mon Sep 17 00:00:00 2001 From: akemidx Date: Tue, 28 Nov 2023 17:15:51 -0500 Subject: [PATCH 19/53] translating no group message on user edit page --- resources/lang/en/admin/settings/general.php | 1 + resources/lang/en/admin/users/table.php | 1 + resources/views/users/edit.blade.php | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/lang/en/admin/settings/general.php b/resources/lang/en/admin/settings/general.php index 64d0aef53e..c8d6306036 100644 --- a/resources/lang/en/admin/settings/general.php +++ b/resources/lang/en/admin/settings/general.php @@ -9,6 +9,7 @@ return [ 'ad_append_domain_help' => 'User isn\'t required to write "username@domain.local", they can just type "username".', 'admin_cc_email' => 'CC Email', 'admin_cc_email_help' => 'If you would like to send a copy of checkin/checkout emails that are sent to users to an additional email account, enter it here. Otherwise leave this field blank.', + 'admin_settings' => 'Admin Settings', 'is_ad' => 'This is an Active Directory server', 'alerts' => 'Alerts', 'alert_title' => 'Update Notification Settings', diff --git a/resources/lang/en/admin/users/table.php b/resources/lang/en/admin/users/table.php index 21e2154280..b8b919bf28 100644 --- a/resources/lang/en/admin/users/table.php +++ b/resources/lang/en/admin/users/table.php @@ -21,6 +21,7 @@ return array( 'manager' => 'Manager', 'managed_locations' => 'Managed Locations', 'name' => 'Name', + 'nogroup' => 'No groups have been created yet. To add one, visit: ', 'notes' => 'Notes', 'password_confirm' => 'Confirm Password', 'password' => 'Password', diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index a8b5ddf05e..1ea6d54100 100755 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -553,7 +553,7 @@ @endif @else -

No groups have been created yet. Visit Admin Settings > Permission Groups to add one.

+

{{ trans('admin/users/table.nogroup') }} {{ trans('admin/settings/general.admin_settings') }} > {{ trans('general.groups') }}

@endif From 63065bab5d32beed747b5907e7a79ab382e41c90 Mon Sep 17 00:00:00 2001 From: akemidx Date: Tue, 28 Nov 2023 17:51:43 -0500 Subject: [PATCH 20/53] adding in icons for clarity, since there are two places called settings --- 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 1ea6d54100..60a882ea62 100755 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -553,7 +553,7 @@ @endif @else -

{{ trans('admin/users/table.nogroup') }} {{ trans('admin/settings/general.admin_settings') }} > {{ trans('general.groups') }}

+

{{ trans('admin/users/table.nogroup') }} {{ trans('admin/settings/general.admin_settings') }} > {{ trans('general.groups') }}

@endif From 3152df2c48bf5d1f01c9e66bb9d9b84c7a06a6d4 Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 29 Nov 2023 10:07:47 +0000 Subject: [PATCH 21/53] Created mutator for requestable attribute Signed-off-by: snipe --- app/Models/Asset.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index f23ff52f64..029f449d50 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -921,6 +921,27 @@ class Asset extends Depreciable return $cost; } + /** + * ----------------------------------------------- + * BEGIN MUTATORS + * ----------------------------------------------- + **/ + + /** + * This sets the requestable to a boolean 0 or 1. This accounts for forms or API calls that + * explicitly pass the requestable field but it has a null or empty value. + * + * This will also correctly parse a 1/0 if "true"/"false" is passed. + * + * @param $value + * @return void + */ + public function setRequestableAttribute($value) + { + $this->attributes['requestable'] = (int) filter_var($value, FILTER_VALIDATE_BOOLEAN); + } + + /** * ----------------------------------------------- * BEGIN QUERY SCOPES From 5b4d6b346bef0f12262265d8187e927ba858eb4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Pittet?= Date: Wed, 29 Nov 2023 11:03:12 -0800 Subject: [PATCH 22/53] Update for CVE-2023-49316 by upgrading phpseclib/phpseclib (3.0.14 => 3.0.34) --- composer.lock | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/composer.lock b/composer.lock index 7ca88da10f..222f27d3c9 100644 --- a/composer.lock +++ b/composer.lock @@ -7011,16 +7011,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.14", + "version": "3.0.34", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "2f0b7af658cbea265cbb4a791d6c29a6613f98ef" + "reference": "56c79f16a6ae17e42089c06a2144467acc35348a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/2f0b7af658cbea265cbb4a791d6c29a6613f98ef", - "reference": "2f0b7af658cbea265cbb4a791d6c29a6613f98ef", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56c79f16a6ae17e42089c06a2144467acc35348a", + "reference": "56c79f16a6ae17e42089c06a2144467acc35348a", "shasum": "" }, "require": { @@ -7032,6 +7032,7 @@ "phpunit/phpunit": "*" }, "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", @@ -7100,7 +7101,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.14" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.34" }, "funding": [ { @@ -7116,7 +7117,7 @@ "type": "tidelift" } ], - "time": "2022-04-04T05:15:45+00:00" + "time": "2023-11-27T11:13:31+00:00" }, { "name": "phpspec/prophecy", @@ -16600,5 +16601,5 @@ "ext-pdo": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } From 4a19f23e7c7708732fe21d5f53bf237ce66c5710 Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Wed, 29 Nov 2023 11:30:02 -0800 Subject: [PATCH 23/53] fixes for black dark theme --- .../assets/less/skins/skin-black-dark.less | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/resources/assets/less/skins/skin-black-dark.less b/resources/assets/less/skins/skin-black-dark.less index 69a393e80d..6f0a2204b2 100644 --- a/resources/assets/less/skins/skin-black-dark.less +++ b/resources/assets/less/skins/skin-black-dark.less @@ -124,11 +124,11 @@ a { --button-primary: darken(@black, 25%); --button-hover: darken(@black, 30%); --header: @black; /* Use same as Header picker */ - --text-main: #BBB; + --text-main: #fff; --text-sub: #9b9b9b; - --link: #AAA; /* Use same as Header picker, lighten by 70% */ - --visited-link: lighten(@black, 40%); /* Use same as Header picker, lighten by 70% */ - --hover-link: lighten(@black, 45%); /* Use same as Header picker, lighten by 70% */ + --link: #fff; /* Use same as Header picker, lighten by 70% */ + --visited-link: #fff; /* Use same as Header picker, lighten by 70% */ + --hover-link: #949494; /* Use same as Header picker, lighten by 70% */ --nav-link: #FFF; /* Use same as Header picker */ --light-link: #fff; /* Use same as Header picker */ } @@ -193,18 +193,6 @@ h2.task_menu{ color: var(--text-main); } -a:link { - color: var(--link); -} - -a:visited { - color: var(--nav-link); -} - -a:hover { - color: var(--hover-link); -} - .btn-primary.hover { color: var(--nav-link); } @@ -318,8 +306,11 @@ input[type=text], input[type=search] { background-color: var(--back-sub); color: var(--text-main); } +.search-highlight, .search-highlight:hover{ + background-color: var(--back-sub) !important; +} .input-group, .input-group-addon { - background-color: var(--back-sub)!important; + background-color: var(--back-sub); color: var(--text-main); } #licensesTable>tbody>tr>td>nobr>a>i.fa { @@ -363,11 +354,11 @@ input[type=text], input[type=search] { } .select2-container--default .select2-results__option[aria-selected=true], .select2-container--default .select2-results__option[aria-selected=true]:hover { background-color: var(--back-sub); - color: var(--header); + color: var(--nav-link); } .select2-container--default .select2-results__option--highlighted[aria-selected] { - background-color: var(--header); - color: var(--back-main); + background-color: var(--back-sub); + color: var(--visited-link); } .select2-container--default .select2-selection--single .select2-selection__rendered { color: var(--text-main); @@ -426,9 +417,6 @@ a { color: var(--hover-link); text-decoration: underline; } - &:visited { - color: var(--visited-link) - } } .row-striped { @@ -463,4 +451,7 @@ a { } div.container.row-new-striped{ background-color: var(--back-sub); +} +.table > thead > tr > td.danger, .table > tbody > tr > td.danger, .table > tfoot > tr > td.danger, .table > thead > tr > th.danger, .table > tbody > tr > th.danger, .table > tfoot > tr > th.danger, .table > thead > tr.danger > td, .table > tbody > tr.danger > td, .table > tfoot > tr.danger > td, .table > thead > tr.danger > th, .table > tbody > tr.danger > th, .table > tfoot > tr.danger > th { + background-color: var(--back-sub); } \ No newline at end of file From 16da994e28649896ee8369abd8a5754852d30217 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Thu, 30 Nov 2023 14:00:20 +0000 Subject: [PATCH 24/53] Add LDAP as 'recommended' requirement; flesh out LDAP tests --- composer.json | 3 ++ tests/Support/Settings.php | 22 +++++++++++ tests/Unit/LdapTest.php | 80 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) diff --git a/composer.json b/composer.json index 58c2b6bedc..2a456999e9 100644 --- a/composer.json +++ b/composer.json @@ -74,6 +74,9 @@ "unicodeveloper/laravel-password": "^1.0", "watson/validating": "^6.1" }, + "suggest": { + "ext-ldap": "*" + }, "require-dev": { "brianium/paratest": "^6.6", "fakerphp/faker": "^1.16", diff --git a/tests/Support/Settings.php b/tests/Support/Settings.php index 0ca05a4752..30fe8c7017 100644 --- a/tests/Support/Settings.php +++ b/tests/Support/Settings.php @@ -79,6 +79,28 @@ class Settings ]); } + public function enableAnonymousLdap(): Settings + { + return $this->update([ + 'ldap_enabled' => 1, + 'ldap_server' => 'ldaps://ldap.example.com', +// 'ldap_uname' => 'fake_username', + 'ldap_pword' => Crypt::encrypt("fake_password"), + 'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com' + ]); + } + + public function enableBadPasswordLdap(): Settings + { + return $this->update([ + 'ldap_enabled' => 1, + 'ldap_server' => 'ldaps://ldap.example.com', + 'ldap_uname' => 'fake_username', + 'ldap_pword' => "badly_encrypted_password!", + 'ldap_basedn' => 'CN=Users,DC=ad,DC=example,Dc=com' + ]); + } + /** * @param array $attributes Attributes to modify in the application's settings. */ diff --git a/tests/Unit/LdapTest.php b/tests/Unit/LdapTest.php index 7b94f1aac5..78e829c6e9 100644 --- a/tests/Unit/LdapTest.php +++ b/tests/Unit/LdapTest.php @@ -3,6 +3,7 @@ namespace Tests\Unit; use App\Models\Ldap; +use Exception; use Tests\Support\InteractsWithSettings; use Tests\TestCase; @@ -25,4 +26,83 @@ class LdapTest extends TestCase $blah = Ldap::connectToLdap(); $this->assertEquals('hello',$blah,"LDAP_connect should return 'hello'"); } + + // other test cases - with/without client-side certs? + // with/without LDAP version 3? + // with/without ignore cert validation? + // test (and mock) ldap_start_tls() ? + + public function testBindAdmin() + { + $this->settings->enableLdap(); + $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); + $this->assertNull(Ldap::bindAdminToLdap("dummy")); + } + + public function testBindBad() + { + $this->settings->enableLdap(); + $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(false); + $this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception"); + $this->expectExceptionMessage("Could not bind to LDAP:"); + + $this->assertNull(Ldap::bindAdminToLdap("dummy")); + } + // other test cases - test donked password? + + public function testAnonymousBind() + { + //todo - would be nice to introspect somehow to make sure the right parameters were passed? + $this->settings->enableAnonymousLdap(); + $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); + $this->assertNull(Ldap::bindAdminToLdap("dummy")); + } + + public function testBadAnonymousBind() + { + $this->settings->enableAnonymousLdap(); + $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(false); + $this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception"); + $this->expectExceptionMessage("Could not bind to LDAP:"); + + $this->assertNull(Ldap::bindAdminToLdap("dummy")); + } + + public function testBadEncryptedPassword() + { + $this->settings->enableBadPasswordLdap(); + + $this->expectExceptionMessage("Your app key has changed"); + $this->assertNull(Ldap::bindAdminToLdap("dummy")); + } + + public function testFindAndBind() + { + $this->settings->enableLdap(); + + $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect"); + $ldap_connect->expects($this->once())->willReturn('hello'); + + $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); + $ldap_set_option->expects($this->exactly(3)); + + $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); + + $this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(true); + + $this->getFunctionMock("App\\Models", "ldap_first_entry")->expects($this->once())->willReturn(true); + + $this->getFunctionMock("App\\Models", "ldap_get_attributes")->expects($this->once())->willReturn( + [ + "count" => 1, + 0 => [ + 'sn' => 'Surname', + 'firstName' => 'FirstName' + ] + ] + ); + + $results = Ldap::findAndBindUserLdap("username","password"); + $this->assertEqualsCanonicalizing(["count" =>1,0 =>['sn' => 'Surname','firstname' => 'FirstName']],$results); + } } From 5a60df55d1136d014e912d7c7c44e083097f1ff1 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Thu, 30 Nov 2023 16:09:37 +0000 Subject: [PATCH 25/53] Add more LDAP tests - including pagination(!) --- tests/Unit/LdapTest.php | 102 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tests/Unit/LdapTest.php b/tests/Unit/LdapTest.php index 78e829c6e9..bae4f3ff4c 100644 --- a/tests/Unit/LdapTest.php +++ b/tests/Unit/LdapTest.php @@ -105,4 +105,106 @@ class LdapTest extends TestCase $results = Ldap::findAndBindUserLdap("username","password"); $this->assertEqualsCanonicalizing(["count" =>1,0 =>['sn' => 'Surname','firstname' => 'FirstName']],$results); } + + public function testFindAndBindBadPassword() + { + $this->settings->enableLdap(); + + $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect"); + $ldap_connect->expects($this->once())->willReturn('hello'); + + $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); + $ldap_set_option->expects($this->exactly(3)); + + // note - we return FALSE first, to simulate a bad-bind, then TRUE the second time to simulate a successful admin bind + $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->exactly(2))->willReturn(false, true); + +// $this->getFunctionMock("App\\Models","ldap_error")->expects($this->once())->willReturn("exception"); + + +// $this->expectExceptionMessage("exception"); + $results = Ldap::findAndBindUserLdap("username","password"); + $this->assertFalse($results); + } + + public function testFindAndBindCannotFindSelf() + { + $this->settings->enableLdap(); + + $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect"); + $ldap_connect->expects($this->once())->willReturn('hello'); + + $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); + $ldap_set_option->expects($this->exactly(3)); + + $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); + + $this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(false); + + $this->expectExceptionMessage("Could not search LDAP:"); + $results = Ldap::findAndBindUserLdap("username","password"); + $this->assertFalse($results); + } + + //maybe should do an AD test as well? + + public function testFindLdapUsers() + { + $this->settings->enableLdap(); + + $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect"); + $ldap_connect->expects($this->once())->willReturn('hello'); + + $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); + $ldap_set_option->expects($this->exactly(3)); + + $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); + + $this->getFunctionMock("App\\Models", "ldap_search")->expects($this->once())->willReturn(["stuff"]); + + $this->getFunctionMock("App\\Models", "ldap_parse_result")->expects($this->once())->willReturn(true); + + $this->getFunctionMock("App\\Models", "ldap_get_entries")->expects($this->once())->willReturn(["count" => 1]); + + $results = Ldap::findLdapUsers(); + + $this->assertEqualsCanonicalizing(["count" => 1], $results); + } + + public function testFindLdapUsersPaginated() + { + $this->settings->enableLdap(); + + $ldap_connect = $this->getFunctionMock("App\\Models", "ldap_connect"); + $ldap_connect->expects($this->once())->willReturn('hello'); + + $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); + $ldap_set_option->expects($this->exactly(3)); + + $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); + + $this->getFunctionMock("App\\Models", "ldap_search")->expects($this->exactly(2))->willReturn(["stuff"]); + + $this->getFunctionMock("App\\Models", "ldap_parse_result")->expects($this->exactly(2))->willReturnCallback( + function ($ldapconn, $search_results, $errcode , $matcheddn , $errmsg , $referrals, &$controls) { + static $count = 0; + if($count == 0) { + $count++; + $controls[LDAP_CONTROL_PAGEDRESULTS]['value']['cookie'] = "cookie"; + return ["count" => 1]; + } else { + $controls = []; + return ["count" => 1]; + } + + } + ); + + $this->getFunctionMock("App\\Models", "ldap_get_entries")->expects($this->exactly(2))->willReturn(["count" => 1]); + + $results = Ldap::findLdapUsers(); + + $this->assertEqualsCanonicalizing(["count" => 2], $results); + } + } From 1455331a90e174fa22eaca01414bba841fe258ce Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 30 Nov 2023 18:25:38 +0000 Subject: [PATCH 26/53] Updated dev assets Signed-off-by: snipe --- public/css/dist/skins/skin-black-dark.css | Bin 13302 -> 13669 bytes public/css/dist/skins/skin-black-dark.min.css | Bin 13302 -> 13669 bytes public/mix-manifest.json | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/css/dist/skins/skin-black-dark.css b/public/css/dist/skins/skin-black-dark.css index 3e177356031ef54a14886bf34847e729c8c8057c..f12332df6d4bee567ac56b741eafd4b79b306f01 100644 GIT binary patch delta 504 zcmeyC{xoYtv=DPzTH53|A(hE9gq0`T3QJ7hE5r|Ha|!dZTABdiW*K1?w#^eIXL3(Y zHg=etpei$2UDadqdUg5DGgaTPOnxuPIXOX&b@Fyi=a5eQWH}^bP}8n7#K;8z=K(QO diff --git a/public/css/dist/skins/skin-black-dark.min.css b/public/css/dist/skins/skin-black-dark.min.css index 3e177356031ef54a14886bf34847e729c8c8057c..f12332df6d4bee567ac56b741eafd4b79b306f01 100644 GIT binary patch delta 504 zcmeyC{xoYtv=DPzTH53|A(hE9gq0`T3QJ7hE5r|Ha|!dZTABdiW*K1?w#^eIXL3(Y zHg=etpei$2UDadqdUg5DGgaTPOnxuPIXOX&b@Fyi=a5eQWH}^bP}8n7#K;8z=K(QO diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 195625f796..fba4c274e9 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -12,7 +12,7 @@ "/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=7d92dea45d94be7e1d4e427c728d335d", "/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=6fe68325d5356197672c27bc77cedcb4", "/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=8ca888bbc050d9680cbb65021382acba", - "/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=bdfc704731682c67645a2248b0b8d2d7", + "/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=b061bb141af3bdb6280c6ee772cf8f4f", "/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=76482123f6c70e866d6b971ba91de7bb", "/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=d419cb63a12dc175d71645c876bfc2ab", "/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=0a82a6ae6bb4e58fe62d162c4fb50397", @@ -37,7 +37,7 @@ "/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=0a82a6ae6bb4e58fe62d162c4fb50397", "/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=d419cb63a12dc175d71645c876bfc2ab", "/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=76482123f6c70e866d6b971ba91de7bb", - "/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=bdfc704731682c67645a2248b0b8d2d7", + "/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=b061bb141af3bdb6280c6ee772cf8f4f", "/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=f677207c6cf9678eb539abecb408c374", "/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=07273f6ca3c698a39e8fc2075af4fa07", "/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=7b315b9612b8fde8f9c5b0ddb6bba690", From fdaa44654dbb705827e39af84c30f7032733413f Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Thu, 30 Nov 2023 10:46:18 -0800 Subject: [PATCH 27/53] changes the table header Serial to Product Key --- resources/views/licenses/checkin.blade.php | 2 +- resources/views/licenses/checkout.blade.php | 2 +- resources/views/users/view.blade.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/views/licenses/checkin.blade.php b/resources/views/licenses/checkin.blade.php index 075eaa6206..8eeea6f9c4 100755 --- a/resources/views/licenses/checkin.blade.php +++ b/resources/views/licenses/checkin.blade.php @@ -36,7 +36,7 @@
- +

@can('viewKeys', $licenseSeat->license) diff --git a/resources/views/licenses/checkout.blade.php b/resources/views/licenses/checkout.blade.php index a2672be427..e85c677420 100755 --- a/resources/views/licenses/checkout.blade.php +++ b/resources/views/licenses/checkout.blade.php @@ -43,7 +43,7 @@

- +

@can('viewKeys', $license) diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php index 0ed5c93b80..5de2d754fb 100755 --- a/resources/views/users/view.blade.php +++ b/resources/views/users/view.blade.php @@ -727,7 +727,7 @@ {{ trans('general.name') }} - {{ trans('admin/hardware/form.serial') }} + {{ trans('admin/licenses/form.license_key') }} {{ trans('general.purchase_cost') }} {{ trans('admin/licenses/form.purchase_order') }} {{ trans('general.order_number') }} From 1e46ecc2ee7594457807d08453bb926ad3ebf3dc Mon Sep 17 00:00:00 2001 From: snipe Date: Mon, 4 Dec 2023 15:33:56 +0000 Subject: [PATCH 28/53] Added eula-pdfs to allow-list Signed-off-by: snipe --- app/Console/Commands/RestoreFromBackup.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Console/Commands/RestoreFromBackup.php b/app/Console/Commands/RestoreFromBackup.php index b1f1753564..a1a18634cc 100644 --- a/app/Console/Commands/RestoreFromBackup.php +++ b/app/Console/Commands/RestoreFromBackup.php @@ -91,6 +91,7 @@ class RestoreFromBackup extends Command 'storage/private_uploads/users', 'storage/private_uploads/licenses', 'storage/private_uploads/signatures', + 'storage/private_uploads/eula-pdfs', ]; $private_files = [ 'storage/oauth-private.key', From 4fd43799b47da14303a8fc4f65033a89f0a59aab Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Mon, 4 Dec 2023 10:56:03 -0800 Subject: [PATCH 29/53] missed one view --- resources/views/account/view-assets.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/account/view-assets.blade.php b/resources/views/account/view-assets.blade.php index 7481e64c4b..54440d9242 100755 --- a/resources/views/account/view-assets.blade.php +++ b/resources/views/account/view-assets.blade.php @@ -491,7 +491,7 @@ {{ trans('general.name') }} - {{ trans('admin/hardware/form.serial') }} + {{ trans('admin/licenses/form.license_key') }} {{ trans('general.category') }} From 7258af20fc219d20e2239389da0fdbe8e0c565fc Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 5 Dec 2023 14:40:49 +0000 Subject: [PATCH 30/53] Added help text to RTD location field Signed-off-by: snipe --- resources/lang/en/general.php | 1 + resources/views/hardware/edit.blade.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 1f2f4322cc..34768b217a 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -492,5 +492,6 @@ return [ 'copy_to_clipboard' => 'Copy to Clipboard', 'copied' => 'Copied!', 'status_compatibility' => 'If assets are already assigned, they cannot be changed to a non-deployable status type and this value change will be skipped.', + 'rtd_location_help' => 'This is the location of the asset when it is not checked out', ]; diff --git a/resources/views/hardware/edit.blade.php b/resources/views/hardware/edit.blade.php index aff215ae26..4c1c1457b6 100755 --- a/resources/views/hardware/edit.blade.php +++ b/resources/views/hardware/edit.blade.php @@ -65,7 +65,7 @@ @endif @include ('partials.forms.edit.notes') - @include ('partials.forms.edit.location-select', ['translated_name' => trans('admin/hardware/form.default_location'), 'fieldname' => 'rtd_location_id']) + @include ('partials.forms.edit.location-select', ['translated_name' => trans('admin/hardware/form.default_location'), 'fieldname' => 'rtd_location_id', 'help_text' => trans('general.rtd_location_help')]) @include ('partials.forms.edit.requestable', ['requestable_text' => trans('admin/hardware/general.requestable')]) From a0de9eb343822b4b98cce197254bc67bb657ea57 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 5 Dec 2023 15:00:04 +0000 Subject: [PATCH 31/53] Updated to alpine 3.18.5 Signed-off-by: snipe --- Dockerfile.alpine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 62a928f8ad..689a65ed44 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -1,4 +1,4 @@ -FROM alpine:3.17.3 +FROM alpine:3.18.5 # Apache + PHP RUN apk add --no-cache \ apache2 \ From 6bd351c5d8917f9728ec89a0b2bbf5fa94b96b8b Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Thu, 7 Dec 2023 14:08:15 +0000 Subject: [PATCH 32/53] Whoops, didn't even add changes - duh --- app/Console/Commands/RestoreFromBackup.php | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/Console/Commands/RestoreFromBackup.php b/app/Console/Commands/RestoreFromBackup.php index a1a18634cc..7108568c5c 100644 --- a/app/Console/Commands/RestoreFromBackup.php +++ b/app/Console/Commands/RestoreFromBackup.php @@ -84,36 +84,36 @@ class RestoreFromBackup extends Command $private_dirs = [ + 'storage/private_uploads/accessories', + 'storage/private_uploads/assetmodels', 'storage/private_uploads/assets', // these are asset _files_, not the pictures. 'storage/private_uploads/audits', + 'storage/private_uploads/components', + 'storage/private_uploads/consumables', + 'storage/private_uploads/eula-pdfs', 'storage/private_uploads/imports', - 'storage/private_uploads/assetmodels', - 'storage/private_uploads/users', 'storage/private_uploads/licenses', 'storage/private_uploads/signatures', - 'storage/private_uploads/eula-pdfs', + 'storage/private_uploads/users', ]; $private_files = [ 'storage/oauth-private.key', 'storage/oauth-public.key', ]; $public_dirs = [ + 'public/uploads/accessories', + 'public/uploads/assets', // these are asset _pictures_, not asset files + 'public/uploads/avatars', + //'public/uploads/barcodes', // we don't want this, let the barcodes be regenerated + 'public/uploads/categories', 'public/uploads/companies', 'public/uploads/components', - 'public/uploads/categories', - 'public/uploads/manufacturers', - //'public/uploads/barcodes', // we don't want this, let the barcodes be regenerated 'public/uploads/consumables', 'public/uploads/departments', - 'public/uploads/avatars', - 'public/uploads/suppliers', - 'public/uploads/assets', // these are asset _pictures_, not asset files 'public/uploads/locations', - 'public/uploads/accessories', - 'public/uploads/models', - 'public/uploads/categories', - 'public/uploads/avatars', 'public/uploads/manufacturers', + 'public/uploads/models', + 'public/uploads/suppliers', ]; $public_files = [ From 778e45c9fd113cc1fdbcb014bfc7abbce1e6fd29 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 7 Dec 2023 19:36:12 +0000 Subject: [PATCH 33/53] Fixed maintenances patch endpoint Signed-off-by: snipe --- .../Api/AssetMaintenancesController.php | 102 +++++------------- app/Models/AssetMaintenance.php | 30 ++++-- resources/lang/en/general.php | 4 + 3 files changed, 54 insertions(+), 82 deletions(-) diff --git a/app/Http/Controllers/Api/AssetMaintenancesController.php b/app/Http/Controllers/Api/AssetMaintenancesController.php index 6da7ce23a1..931e8e51c0 100644 --- a/app/Http/Controllers/Api/AssetMaintenancesController.php +++ b/app/Http/Controllers/Api/AssetMaintenancesController.php @@ -116,41 +116,17 @@ class AssetMaintenancesController extends Controller { $this->authorize('update', Asset::class); // create a new model instance - $assetMaintenance = new AssetMaintenance(); - $assetMaintenance->supplier_id = $request->input('supplier_id'); - $assetMaintenance->is_warranty = $request->input('is_warranty'); - $assetMaintenance->cost = $request->input('cost'); - $assetMaintenance->notes = e($request->input('notes')); - $asset = Asset::find(e($request->input('asset_id'))); - - if (! Company::isCurrentUserHasAccess($asset)) { - return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot add a maintenance for that asset')); - } - - // Save the asset maintenance data - $assetMaintenance->asset_id = $request->input('asset_id'); - $assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type'); - $assetMaintenance->title = $request->input('title'); - $assetMaintenance->start_date = $request->input('start_date'); - $assetMaintenance->completion_date = $request->input('completion_date'); - $assetMaintenance->user_id = Auth::id(); - - if (($assetMaintenance->completion_date !== null) - && ($assetMaintenance->start_date !== '') - && ($assetMaintenance->start_date !== '0000-00-00') - ) { - $startDate = Carbon::parse($assetMaintenance->start_date); - $completionDate = Carbon::parse($assetMaintenance->completion_date); - $assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate); - } + $maintenance = new AssetMaintenance(); + $maintenance->fill($request->all()); + $maintenance->user_id = Auth::id(); // Was the asset maintenance created? - if ($assetMaintenance->save()) { - return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.create.success'))); + if ($maintenance->save()) { + return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/asset_maintenances/message.create.success'))); } - return response()->json(Helper::formatStandardApiResponse('error', null, $assetMaintenance->getErrors())); + return response()->json(Helper::formatStandardApiResponse('error', null, $maintenance->getErrors())); } @@ -158,65 +134,39 @@ class AssetMaintenancesController extends Controller * Validates and stores an update to an asset maintenance * * @author A. Gianotto - * @param int $assetMaintenanceId + * @param int $id * @param int $request * @version v1.0 * @since [v4.0] * @return string JSON */ - public function update(Request $request, $assetMaintenanceId = null) + public function update(Request $request, $id) { $this->authorize('update', Asset::class); - // Check if the asset maintenance exists - $assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId); - if (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) { - return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot edit a maintenance for that asset')); - } + if ($maintenance = AssetMaintenance::with('asset')->find($id)) { - $assetMaintenance->supplier_id = e($request->input('supplier_id')); - $assetMaintenance->is_warranty = e($request->input('is_warranty')); - $assetMaintenance->cost = $request->input('cost'); - $assetMaintenance->notes = e($request->input('notes')); - - $asset = Asset::find(request('asset_id')); - - if (! Company::isCurrentUserHasAccess($asset)) { - return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot edit a maintenance for that asset')); - } - - // Save the asset maintenance data - $assetMaintenance->asset_id = $request->input('asset_id'); - $assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type'); - $assetMaintenance->title = $request->input('title'); - $assetMaintenance->start_date = $request->input('start_date'); - $assetMaintenance->completion_date = $request->input('completion_date'); - - if (($assetMaintenance->completion_date == null) - ) { - if (($assetMaintenance->asset_maintenance_time !== 0) - || (! is_null($assetMaintenance->asset_maintenance_time)) - ) { - $assetMaintenance->asset_maintenance_time = null; + // Can this user manage this asset? + if (! Company::isCurrentUserHasAccess($maintenance->asset)) { + return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.action_permission_denied', ['item_type' => trans('admin/asset_maintenances/general.maintenance'), 'id' => $id, 'action' => trans('general.edit')]))); } + + // The asset this miantenance is attached to is not valid or has been deleted + if (!$maintenance->asset) { + return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('general.asset'), 'id' => $id]))); + } + + $maintenance->fill($request->all()); + + if ($maintenance->save()) { + return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/asset_maintenances/message.edit.success'))); + } + + return response()->json(Helper::formatStandardApiResponse('error', null, $maintenance->getErrors())); } - if (($assetMaintenance->completion_date !== null) - && ($assetMaintenance->start_date !== '') - && ($assetMaintenance->start_date !== '0000-00-00') - ) { - $startDate = Carbon::parse($assetMaintenance->start_date); - $completionDate = Carbon::parse($assetMaintenance->completion_date); - $assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate); - } + return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('admin/asset_maintenances/general.maintenance'), 'id' => $id]))); - // Was the asset maintenance created? - if ($assetMaintenance->save()) { - return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.edit.success'))); - - } - - return response()->json(Helper::formatStandardApiResponse('error', null, $assetMaintenance->getErrors())); } /** diff --git a/app/Models/AssetMaintenance.php b/app/Models/AssetMaintenance.php index 292e529571..79920ffe5d 100644 --- a/app/Models/AssetMaintenance.php +++ b/app/Models/AssetMaintenance.php @@ -20,10 +20,9 @@ class AssetMaintenance extends Model implements ICompanyableChild use SoftDeletes; use CompanyableChildTrait; use ValidatingTrait; - protected $casts = [ - 'start_date' => 'datetime', - 'completion_date' => 'datetime', - ]; + + + protected $table = 'asset_maintenances'; protected $rules = [ 'asset_id' => 'required|integer', @@ -31,12 +30,31 @@ class AssetMaintenance extends Model implements ICompanyableChild 'asset_maintenance_type' => 'required', 'title' => 'required|max:100', 'is_warranty' => 'boolean', - 'start_date' => 'required|date', - 'completion_date' => 'nullable|date', + 'start_date' => 'required|date_format:Y-m-d', + 'completion_date' => 'date_format:Y-m-d|nullable', 'notes' => 'string|nullable', 'cost' => 'numeric|nullable', ]; + + /** + * The attributes that are mass assignable. + * + * @var array + */ + protected $fillable = [ + 'title', + 'asset_id', + 'supplier_id', + 'asset_maintenance_type', + 'is_warranty', + 'start_date', + 'completed_date', + 'asset_maintenance_time', + 'notes', + 'cost', + ]; + use Searchable; /** diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 34768b217a..7ee5ca1029 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -493,5 +493,9 @@ return [ 'copied' => 'Copied!', 'status_compatibility' => 'If assets are already assigned, they cannot be changed to a non-deployable status type and this value change will be skipped.', 'rtd_location_help' => 'This is the location of the asset when it is not checked out', + 'item_not_found' => ':item_type ID :id does not exist or has been deleted', + 'action_permission_denied' => 'You do not have permission to :action :item_type ID :id', + 'action_permission_generic' => 'You do not have permission to :action this :item_type', + 'edit' => 'edit', ]; From dc836895531a3157ff9fea12ca6c29e1f46cf3af Mon Sep 17 00:00:00 2001 From: akemidx Date: Thu, 7 Dec 2023 17:50:25 -0500 Subject: [PATCH 34/53] changing log level from ERROR to LOG --- app/Helpers/Helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 800a2491d4..b015f988b3 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -354,7 +354,7 @@ class Helper if ($index >= $total_colors) { - \Log::error('Status label count is '.$index.' and exceeds the allowed count of 266.'); + \Log::log('Status label count is '.$index.' and exceeds the allowed count of 266.'); //patch fix for array key overflow (color count starts at 1, array starts at 0) $index = $index - $total_colors - 1; From f112e31b46b1b1e514878c5ce0105c508ef761f3 Mon Sep 17 00:00:00 2001 From: akemidx Date: Thu, 7 Dec 2023 17:56:10 -0500 Subject: [PATCH 35/53] changing log level from ERROR to LOG --- app/Helpers/Helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index b015f988b3..c7aa5af04a 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -354,7 +354,7 @@ class Helper if ($index >= $total_colors) { - \Log::log('Status label count is '.$index.' and exceeds the allowed count of 266.'); + \Log::info('Status label count is '.$index.' and exceeds the allowed count of 266.'); //patch fix for array key overflow (color count starts at 1, array starts at 0) $index = $index - $total_colors - 1; From aa4aaf69b031bd6eb4360a6c0f80e03de1882466 Mon Sep 17 00:00:00 2001 From: snipe Date: Fri, 8 Dec 2023 08:58:45 +0000 Subject: [PATCH 36/53] Fixed typo Signed-off-by: snipe --- app/Models/AssetMaintenance.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/AssetMaintenance.php b/app/Models/AssetMaintenance.php index 79920ffe5d..5da663fc4b 100644 --- a/app/Models/AssetMaintenance.php +++ b/app/Models/AssetMaintenance.php @@ -49,7 +49,7 @@ class AssetMaintenance extends Model implements ICompanyableChild 'asset_maintenance_type', 'is_warranty', 'start_date', - 'completed_date', + 'completion_date', 'asset_maintenance_time', 'notes', 'cost', From 5eb08d9568f59e29d8522476a1903b48780d1d87 Mon Sep 17 00:00:00 2001 From: Godfrey M Date: Mon, 11 Dec 2023 11:14:55 -0800 Subject: [PATCH 37/53] added a missing table header for checkout --- resources/views/hardware/requested.blade.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/views/hardware/requested.blade.php b/resources/views/hardware/requested.blade.php index dcc8a01936..83ea30090f 100644 --- a/resources/views/hardware/requested.blade.php +++ b/resources/views/hardware/requested.blade.php @@ -46,7 +46,8 @@ {{ trans('admin/hardware/form.expected_checkin') }} {{ trans('admin/hardware/table.requesting_user') }} {{ trans('admin/hardware/table.requested_date') }} - {{ trans('button.actions') }} + {{ trans('button.actions') }} + {{ trans('general.checkout') }} From 456e6979f0011fd1f6c81faaf6407998acd7c8e8 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 12 Dec 2023 00:12:06 +0000 Subject: [PATCH 38/53] Updated import icons Signed-off-by: snipe --- resources/lang/en/general.php | 1 + resources/views/layouts/default.blade.php | 2 +- resources/views/livewire/importer.blade.php | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 7ee5ca1029..023e9c052c 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -156,6 +156,7 @@ return [ 'image_filetypes_help' => 'Accepted filetypes are jpg, webp, png, gif, and svg. Max upload size allowed is :size.', 'unaccepted_image_type' => 'This image file was not readable. Accepted filetypes are jpg, webp, png, gif, and svg. The mimetype of this file is: :mimetype.', 'import' => 'Import', + 'import_this_file' => 'Map fields and process this file', 'importing' => 'Importing', 'importing_help' => 'You can import assets, accessories, licenses, components, consumables, and users via CSV file.

The CSV should be comma-delimited and formatted with headers that match the ones in the
sample CSVs in the documentation.', 'import-history' => 'Import History', diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index 3fe1b3845e..90e20d5d9d 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -624,7 +624,7 @@ @can('import') - + {{ trans('general.import') }} diff --git a/resources/views/livewire/importer.blade.php b/resources/views/livewire/importer.blade.php index 7bc88a88aa..976d1ffdde 100644 --- a/resources/views/livewire/importer.blade.php +++ b/resources/views/livewire/importer.blade.php @@ -129,8 +129,8 @@ {{ Helper::getFormattedDateObject($currentFile->created_at, 'datetime', false) }} {{ Helper::formatFilesizeUnits($currentFile->filesize) }} -