From 362f14a01d044ad60c13c7e89e4016b566269adc Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 8 Apr 2025 01:59:33 +0100 Subject: [PATCH] Manually invoke a validator Signed-off-by: snipe --- app/Http/Controllers/Api/AssetsController.php | 85 ++++++++------- .../Controllers/Assets/AssetsController.php | 103 +++++++++++------- 2 files changed, 111 insertions(+), 77 deletions(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index c20568ed7..d60ded391 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -34,6 +34,7 @@ use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Route; use App\View\Label; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\Validator; /** @@ -1081,22 +1082,6 @@ class AssetsController extends Controller $originalValues = $asset->getRawOriginal(); - /** - * Even though we do a save() further down, we don't want to log this as a "normal" asset update, - * which would trigger the Asset Observer and would log an asset *update* log entry (because the - * de-normed fields like next_audit_date on the asset itself will change on save()) *in addition* to - * the audit log entry we're creating through this controller. - * - * To prevent this double-logging (one for update and one for audit), we skip the observer and bypass - * that de-normed update log entry by using unsetEventDispatcher(), BUT invoking unsetEventDispatcher() - * will bypass normal model-level validation that's usually handled at the observer ) - * - * We handle validation on the save() by checking if the asset is valid via the ->isValid() method, - * which manually invokes Watson Validating to make sure the asset's model is valid. - * - * @see \App\Observers\AssetObserver::updating() - */ - $asset->unsetEventDispatcher(); $asset->next_audit_date = $dt; if ($request->filled('next_audit_date')) { @@ -1125,29 +1110,58 @@ class AssetsController extends Controller * Validation for these fields is handled through the AssetRequest form request * $model = AssetModel::find($request->get('model_id')); */ - if (($asset->model) && ($asset->model->fieldset)) { $payload['custom_fields'] = []; foreach ($asset->model->fieldset->fields as $field) { - if ($field->field_encrypted == '1') { - if (Gate::allows('assets.view.encrypted_custom_fields')) { + if (($field->display_audit=='1') && ($request->has($field->db_column))) { + if ($field->field_encrypted == '1') { + if (Gate::allows('assets.view.encrypted_custom_fields')) { + if (is_array($request->input($field->db_column))) { + $asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column))); + } else { + $asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column)); + } + } + } else { if (is_array($request->input($field->db_column))) { - $asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column))); + $asset->{$field->db_column} = implode(', ', $request->input($field->db_column)); } else { - $asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column)); + $asset->{$field->db_column} = $request->input($field->db_column); } } - } else { - if (is_array($request->input($field->db_column))) { - $asset->{$field->db_column} = implode(', ', $request->input($field->db_column)); - } else { - $asset->{$field->db_column} = $request->input($field->db_column); - } + $payload['custom_fields'][$field->db_column] = $request->input($field->db_column); } - $payload['custom_fields'][$field->db_column] = $request->input($field->db_column); - } - } + } + } + + // Validate custom fields + Validator::make($asset->toArray(), $asset->customFieldValidationRules())->validate(); + + // Validate the rest of the data before we turn off the event dispatcher + if ($asset->isInvalid()) { + return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors())); + } + + + /** + * Even though we do a save() further down, we don't want to log this as a "normal" asset update, + * which would trigger the Asset Observer and would log an asset *update* log entry (because the + * de-normed fields like next_audit_date on the asset itself will change on save()) *in addition* to + * the audit log entry we're creating through this controller. + * + * To prevent this double-logging (one for update and one for audit), we skip the observer and bypass + * that de-normed update log entry by using unsetEventDispatcher(), BUT invoking unsetEventDispatcher() + * will bypass normal model-level validation that's usually handled at the observer) + * + * We handle validation on the save() by checking if the asset is valid via the ->isValid() method, + * which manually invokes Watson Validating to make sure the asset's model is valid. + * + * @see \App\Observers\AssetObserver::updating() + * @see \App\Models\Asset::save() + */ + + $asset->unsetEventDispatcher(); /** @@ -1159,19 +1173,12 @@ class AssetsController extends Controller return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/hardware/message.audit.success'))); } - // Asset failed validation or was not able to be saved - return response()->json(Helper::formatStandardApiResponse('error', [ - 'asset_tag' => e($asset->asset_tag), - 'error' => $asset->getErrors()->first(), - ], trans('admin/hardware/message.audit.error', ['error' => $asset->getErrors()->first()])), 200); } // No matching asset for the asset tag that was passed. - return response()->json(Helper::formatStandardApiResponse('error', [ - 'asset_tag' => e($request->input('asset_tag')), - 'error' => trans('admin/hardware/message.audit.error'), - ], trans('admin/hardware/message.audit.error', ['error' => trans('admin/hardware/message.does_not_exist')])), 200); + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200); + } diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index 9578acea6..23b438707 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -6,6 +6,7 @@ use App\Events\CheckoutableCheckedIn; use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Http\Requests\ImageUploadRequest; +use App\Http\Requests\UpdateAssetRequest; use App\Models\Actionlog; use App\Http\Requests\UploadFileRequest; use Illuminate\Support\Facades\Log; @@ -390,26 +391,26 @@ class AssetsController extends Controller $asset = $request->handleImages($asset); // Update custom fields in the database. - // Validation for these fields is handlded through the AssetRequest form request // FIXME: No idea why this is returning a Builder error on db_column_name. // Need to investigate and fix. Using static method for now. $model = AssetModel::find($request->get('model_id')); if (($model) && ($model->fieldset)) { foreach ($model->fieldset->fields as $field) { - - if ($field->field_encrypted == '1') { - if (Gate::allows('assets.view.encrypted_custom_fields')) { - if (is_array($request->input($field->db_column))) { - $asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column))); - } else { - $asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column)); + if ($request->has($field->db_column)) { + if ($field->field_encrypted == '1') { + if (Gate::allows('assets.view.encrypted_custom_fields')) { + if (is_array($request->input($field->db_column))) { + $asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column))); + } else { + $asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column)); + } } - } - } else { - if (is_array($request->input($field->db_column))) { - $asset->{$field->db_column} = implode(', ', $request->input($field->db_column)); } else { - $asset->{$field->db_column} = $request->input($field->db_column); + if (is_array($request->input($field->db_column))) { + $asset->{$field->db_column} = implode(', ', $request->input($field->db_column)); + } else { + $asset->{$field->db_column} = $request->input($field->db_column); + } } } } @@ -865,13 +866,6 @@ class AssetsController extends Controller return view('hardware/quickscan-checkin')->with('statusLabel_list', Helper::statusLabelList()); } - public function audit(Asset $asset) - { - $settings = Setting::getSettings(); - $this->authorize('audit', Asset::class); - $dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString(); - return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list'); - } public function dueForAudit() { @@ -888,19 +882,59 @@ class AssetsController extends Controller } - public function auditStore(UploadFileRequest $request, Asset $asset) + public function audit(Asset $asset) { + $settings = Setting::getSettings(); + $this->authorize('audit', Asset::class); + $dt = Carbon::now()->addMonths($settings->audit_interval)->toDateString(); + return view('hardware/audit')->with('asset', $asset)->with('item', $asset)->with('next_audit_date', $dt)->with('locations_list'); + } + + public function auditStore(UpdateAssetRequest $request, Asset $asset) + { + $this->authorize('audit', Asset::class); - $rules = [ - 'location_id' => 'exists:locations,id|nullable|numeric', - 'next_audit_date' => 'date|nullable', - ]; + $originalValues = $asset->getRawOriginal(); - $validator = Validator::make($request->all(), $rules); + $asset->next_audit_date = $request->input('next_audit_date'); + $asset->last_audit_date = date('Y-m-d H:i:s'); - if ($validator->fails()) { - return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all())); + // Check to see if they checked the box to update the physical location, + // not just note it in the audit notes + if ($request->input('update_location') == '1') { + $asset->location_id = $request->input('location_id'); + } + + // Update custom fields in the database + if (($asset->model) && ($asset->model->fieldset)) { + foreach ($asset->model->fieldset->fields as $field) { + if (($field->display_audit=='1') && ($request->has($field->db_column))) { + if ($field->field_encrypted == '1') { + if (Gate::allows('assets.view.encrypted_custom_fields')) { + if (is_array($request->input($field->db_column))) { + $asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column))); + } else { + $asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column)); + } + } + } else { + if (is_array($request->input($field->db_column))) { + $asset->{$field->db_column} = implode(', ', $request->input($field->db_column)); + } else { + $asset->{$field->db_column} = $request->input($field->db_column); + } + } + } + } + } + + // Validate custom fields + Validator::make($asset->toArray(), $asset->customFieldValidationRules())->validate(); + + // Validate the rest of the data before we turn off the event dispatcher + if ($asset->isInvalid()) { + return redirect()->back()->withInput()->withErrors($asset->getErrors()); } /** @@ -917,18 +951,11 @@ class AssetsController extends Controller * which manually invokes Watson Validating to make sure the asset's model is valid. * * @see \App\Observers\AssetObserver::updating() + * @see \App\Models\Asset::save() */ + $asset->unsetEventDispatcher(); - $asset->next_audit_date = $request->input('next_audit_date'); - $asset->last_audit_date = date('Y-m-d H:i:s'); - - // Check to see if they checked the box to update the physical location, - // not just note it in the audit notes - if ($request->input('update_location') == '1') { - $asset->location_id = $request->input('location_id'); - } - /** * Invoke Watson Validating to check the asset itself and check to make sure it saved correctly. @@ -942,7 +969,7 @@ class AssetsController extends Controller $file_name = $request->handleFile('private_uploads/audits/', 'audit-'.$asset->id, $request->file('image')); } - $asset->logAudit($request->input('note'), $request->input('location_id'), $file_name); + $asset->logAudit($request->input('note'), $request->input('location_id'), $file_name, $originalValues); return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success')); }