Manually invoke a validator

Signed-off-by: snipe <snipe@snipe.net>
This commit is contained in:
snipe 2025-04-08 01:59:33 +01:00
parent 226ad52f07
commit 362f14a01d
2 changed files with 111 additions and 77 deletions

View file

@ -34,6 +34,7 @@ use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use App\View\Label; use App\View\Label;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
/** /**
@ -1081,22 +1082,6 @@ class AssetsController extends Controller
$originalValues = $asset->getRawOriginal(); $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; $asset->next_audit_date = $dt;
if ($request->filled('next_audit_date')) { 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 * Validation for these fields is handled through the AssetRequest form request
* $model = AssetModel::find($request->get('model_id')); * $model = AssetModel::find($request->get('model_id'));
*/ */
if (($asset->model) && ($asset->model->fieldset)) { if (($asset->model) && ($asset->model->fieldset)) {
$payload['custom_fields'] = []; $payload['custom_fields'] = [];
foreach ($asset->model->fieldset->fields as $field) { foreach ($asset->model->fieldset->fields as $field) {
if ($field->field_encrypted == '1') { if (($field->display_audit=='1') && ($request->has($field->db_column))) {
if (Gate::allows('assets.view.encrypted_custom_fields')) { 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))) { 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 { } else {
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column)); $asset->{$field->db_column} = $request->input($field->db_column);
} }
} }
} else { $payload['custom_fields'][$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);
}
} }
$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'))); 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. // No matching asset for the asset tag that was passed.
return response()->json(Helper::formatStandardApiResponse('error', [ return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
'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);
} }

View file

@ -6,6 +6,7 @@ use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\UpdateAssetRequest;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Http\Requests\UploadFileRequest; use App\Http\Requests\UploadFileRequest;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@ -390,26 +391,26 @@ class AssetsController extends Controller
$asset = $request->handleImages($asset); $asset = $request->handleImages($asset);
// Update custom fields in the database. // 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. // FIXME: No idea why this is returning a Builder error on db_column_name.
// Need to investigate and fix. Using static method for now. // Need to investigate and fix. Using static method for now.
$model = AssetModel::find($request->get('model_id')); $model = AssetModel::find($request->get('model_id'));
if (($model) && ($model->fieldset)) { if (($model) && ($model->fieldset)) {
foreach ($model->fieldset->fields as $field) { foreach ($model->fieldset->fields as $field) {
if ($request->has($field->db_column)) {
if ($field->field_encrypted == '1') { if ($field->field_encrypted == '1') {
if (Gate::allows('assets.view.encrypted_custom_fields')) { if (Gate::allows('assets.view.encrypted_custom_fields')) {
if (is_array($request->input($field->db_column))) { if (is_array($request->input($field->db_column))) {
$asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column))); $asset->{$field->db_column} = Crypt::encrypt(implode(', ', $request->input($field->db_column)));
} else { } else {
$asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column)); $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 { } 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()); 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() 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); $this->authorize('audit', Asset::class);
$rules = [ $originalValues = $asset->getRawOriginal();
'location_id' => 'exists:locations,id|nullable|numeric',
'next_audit_date' => 'date|nullable',
];
$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()) { // Check to see if they checked the box to update the physical location,
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all())); // 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. * which manually invokes Watson Validating to make sure the asset's model is valid.
* *
* @see \App\Observers\AssetObserver::updating() * @see \App\Observers\AssetObserver::updating()
* @see \App\Models\Asset::save()
*/ */
$asset->unsetEventDispatcher(); $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. * 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')); $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')); return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success'));
} }