mirror of
https://github.com/snipe/snipe-it.git
synced 2024-12-24 21:24:13 -08:00
Fixed #8926, #8252 - introduce circular reference check for location parent_id - rebased from #8253 (#8927)
* Fixed #8252 - circular references in location parents * Remove non-translated translation changes * Fix typo * Add loop limit to avoid unforseen infinite loops * Remove check against parent_id in location controllers * Remove the Location->id=null piece (no longer needed) * Fix some formatting and whitespace * Re-introduce accidentally merged-out language file Co-authored-by: Travis Miller <milletr@tulsaschools.org>
This commit is contained in:
parent
d3d96c8285
commit
0329028e2c
|
@ -67,7 +67,6 @@ class LocationsController extends Controller
|
||||||
{
|
{
|
||||||
$this->authorize('create', Location::class);
|
$this->authorize('create', Location::class);
|
||||||
$location = new Location();
|
$location = new Location();
|
||||||
$location->id = null; // This is required to make Laravels different validation work, it errors if the parameter doesn't exist (maybe a bug)?
|
|
||||||
$location->name = $request->input('name');
|
$location->name = $request->input('name');
|
||||||
$location->parent_id = $request->input('parent_id', null);
|
$location->parent_id = $request->input('parent_id', null);
|
||||||
$location->currency = $request->input('currency', '$');
|
$location->currency = $request->input('currency', '$');
|
||||||
|
@ -132,7 +131,6 @@ class LocationsController extends Controller
|
||||||
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update the location data
|
// Update the location data
|
||||||
$location->name = $request->input('name');
|
$location->name = $request->input('name');
|
||||||
$location->parent_id = $request->input('parent_id', null);
|
$location->parent_id = $request->input('parent_id', null);
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Location extends SnipeModel
|
||||||
'address2' => 'max:80|nullable',
|
'address2' => 'max:80|nullable',
|
||||||
'zip' => 'min:3|max:10|nullable',
|
'zip' => 'min:3|max:10|nullable',
|
||||||
'manager_id' => 'exists:users,id|nullable',
|
'manager_id' => 'exists:users,id|nullable',
|
||||||
'parent_id' => 'nullable|exists:locations,id|different:id',
|
'parent_id' => 'non_circular:locations,id'
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
|
|
@ -58,6 +58,52 @@ class ValidationServiceProvider extends ServiceProvider
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Prevent circular references
|
||||||
|
//
|
||||||
|
// Example usage in Location model where parent_id references another Location:
|
||||||
|
//
|
||||||
|
// protected $rules = array(
|
||||||
|
// 'parent_id' => 'non_circular:locations,id,10'
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
Validator::extend('non_circular', function ($attribute, $value, $parameters, $validator) {
|
||||||
|
if (count($parameters) < 2) {
|
||||||
|
throw new \Exception('Required validator parameters: <table>,<primary key>[,depth]');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameters from the rule implementation ($pk will likely be 'id')
|
||||||
|
$table = array_get($parameters, 0);
|
||||||
|
$pk = array_get($parameters, 1);
|
||||||
|
$depth = (int) array_get($parameters, 2, 50);
|
||||||
|
|
||||||
|
// Data from the edited model
|
||||||
|
$data = $validator->getData();
|
||||||
|
|
||||||
|
// The primary key value from the edited model
|
||||||
|
$data_pk = array_get($data, $pk);
|
||||||
|
$value_pk = $value;
|
||||||
|
|
||||||
|
// If we’re editing an existing model and there is a parent value set…
|
||||||
|
while ($data_pk && $value_pk) {
|
||||||
|
|
||||||
|
// It’s not valid for any parent id to be equal to the existing model’s id
|
||||||
|
if ($data_pk == $value_pk) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid accidental infinite loops
|
||||||
|
if (--$depth < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next parent id
|
||||||
|
$value_pk = DB::table($table)->select($attribute)->where($pk, '=', $value_pk)->value($attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Yo dawg. I heard you like validators.
|
// Yo dawg. I heard you like validators.
|
||||||
// This validates the custom validator regex in custom fields.
|
// This validates the custom validator regex in custom fields.
|
||||||
// We're just checking that the regex won't throw an exception, not
|
// We're just checking that the regex won't throw an exception, not
|
||||||
|
|
|
@ -89,6 +89,7 @@ return array(
|
||||||
'uploaded' => 'The :attribute failed to upload.',
|
'uploaded' => 'The :attribute failed to upload.',
|
||||||
'url' => 'The :attribute format is invalid.',
|
'url' => 'The :attribute format is invalid.',
|
||||||
"unique_undeleted" => "The :attribute must be unique.",
|
"unique_undeleted" => "The :attribute must be unique.",
|
||||||
|
"non_circular" => "The :attribute must not create a circular reference.",
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue