diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 3d4db93452..e76d8e5dae 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -150,6 +150,11 @@ class Handler extends ExceptionHandler return redirect()->guest('login'); } + protected function invalidJson($request, ValidationException $exception) + { + return response()->json(Helper::formatStandardApiResponse('error', null, $exception->errors()), 200); + } + /** * A list of the inputs that are never flashed for validation exceptions. diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 6c343731ca..954ba3a4d0 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Api; use App\Events\CheckoutableCheckedIn; +use App\Http\Requests\StoreAssetRequest; use Illuminate\Support\Facades\Gate; use App\Helpers\Helper; use App\Http\Controllers\Controller; @@ -33,6 +34,7 @@ use TCPDF; use Validator; use Route; + /** * This class controls all actions related to assets for * the Snipe-IT Asset Management application. @@ -532,10 +534,8 @@ class AssetsController extends Controller * @since [v4.0] * @return \Illuminate\Http\JsonResponse */ - public function store(ImageUploadRequest $request) + public function store(StoreAssetRequest $request) { - $this->authorize('create', Asset::class); - $asset = new Asset(); $asset->model()->associate(AssetModel::find((int) $request->get('model_id'))); diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php new file mode 100644 index 0000000000..254895f134 --- /dev/null +++ b/app/Http/Requests/StoreAssetRequest.php @@ -0,0 +1,40 @@ +getRules(), + parent::rules(), + ); + + return $rules; + } +} diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 9f15101d33..a7d4d7442a 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -91,7 +91,7 @@ class Asset extends Depreciable protected $rules = [ 'name' => 'max:255|nullable', - 'model_id' => 'required|integer|exists:models,id,deleted_at,NULL', + 'model_id' => 'required|integer|exists:models,id,deleted_at,NULL|not_array', 'status_id' => 'required|integer|exists:status_labels,id', 'company_id' => 'integer|nullable', 'warranty_months' => 'numeric|nullable|digits_between:0,240', @@ -100,7 +100,7 @@ class Asset extends Depreciable 'expected_checkin' => 'date|nullable', 'location_id' => 'exists:locations,id|nullable', 'rtd_location_id' => 'exists:locations,id|nullable', - 'asset_tag' => 'required|min:1|max:255|unique_undeleted', + 'asset_tag' => 'required|min:1|max:255|unique_undeleted:assets,asset_tag', 'purchase_date' => 'date|date_format:Y-m-d|nullable', 'serial' => 'unique_serial|nullable', 'purchase_cost' => 'numeric|nullable|gte:0', diff --git a/app/Providers/ValidationServiceProvider.php b/app/Providers/ValidationServiceProvider.php index 70fa64702e..30c5a0197e 100644 --- a/app/Providers/ValidationServiceProvider.php +++ b/app/Providers/ValidationServiceProvider.php @@ -48,6 +48,8 @@ class ValidationServiceProvider extends ServiceProvider // Unique only if undeleted // This works around the use case where multiple deleted items have the same unique attribute. // (I think this is a bug in Laravel's validator?) + // $parameters is the rule parameters, like `unique_undeleted:users,id` - $parameters[0] is users, $parameters[1] is id + // the UniqueUndeletedTrait prefills these so you can just use `unique_undeleted` in your rules (but this would only work directly in the model) Validator::extend('unique_undeleted', function ($attribute, $value, $parameters, $validator) { if (count($parameters)) { $count = DB::table($parameters[0])->select('id')->where($attribute, '=', $value)->whereNull('deleted_at')->where('id', '!=', $parameters[1])->count(); diff --git a/tests/Feature/Api/Assets/AssetStoreTest.php b/tests/Feature/Api/Assets/AssetStoreTest.php new file mode 100644 index 0000000000..5a68aebccb --- /dev/null +++ b/tests/Feature/Api/Assets/AssetStoreTest.php @@ -0,0 +1,19 @@ +actingAsForApi(User::factory()->create()) + ->postJson(route('api.assets.store')) + ->assertForbidden(); + } +}