authorize('import'); $imports = Import::latest()->get(); return (new ImportsTransformer)->transformImports($imports); } /** * Process and store a CSV upload file. * * @param \Illuminate\Http\Request $request */ public function store() : JsonResponse { $this->authorize('import'); if (! config('app.lock_passwords')) { $files = Request::file('files'); $path = config('app.private_uploads').'/imports'; $results = []; $import = new Import; foreach ($files as $file) { if (! in_array($file->getMimeType(), [ 'application/vnd.ms-excel', 'text/csv', 'application/csv', 'text/x-Algol68', // because wtf CSV files? 'text/plain', 'text/comma-separated-values', 'text/tsv', ])) { $results['error'] = 'File type must be CSV. Uploaded file is '.$file->getMimeType(); return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 422); } //TODO: is there a lighter way to do this? if (! ini_get('auto_detect_line_endings')) { ini_set('auto_detect_line_endings', '1'); } $reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak? try { $import->header_row = $reader->fetchOne(0); } catch (JsonEncodingException $e) { return response()->json( Helper::formatStandardApiResponse( 'error', null, trans('admin/hardware/message.import.header_row_has_malformed_characters') ), 422 ); } //duplicate headers check $duplicate_headers = []; for ($i = 0; $i < count($import->header_row); $i++) { $header = $import->header_row[$i]; if (in_array($header, $import->header_row)) { $found_at = array_search($header, $import->header_row); if ($i > $found_at) { //avoid reporting duplicates twice, e.g. "1 is same as 17! 17 is same as 1!!!" //as well as "1 is same as 1!!!" (which is always true) //has to be > because otherwise the first result of array_search will always be $i itself(!) array_push($duplicate_headers, "Duplicate header '$header' detected, first at column: ".($found_at + 1).', repeats at column: '.($i + 1)); } } } if (count($duplicate_headers) > 0) { return response()->json(Helper::formatStandardApiResponse('error', null, implode('; ', $duplicate_headers)),422); } try { // Grab the first row to display via ajax as the user picks fields $import->first_row = $reader->fetchOne(1); } catch (JsonEncodingException $e) { return response()->json( Helper::formatStandardApiResponse( 'error', null, trans('admin/hardware/message.import.content_row_has_malformed_characters') ), 422 ); } $date = date('Y-m-d-his'); $fixed_filename = str_slug($file->getClientOriginalName()); try { $file->move($path, $date.'-'.$fixed_filename); } catch (FileException $exception) { $results['error'] = trans('admin/hardware/message.upload.error'); if (config('app.debug')) { $results['error'] .= ' '.$exception->getMessage(); } return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 500); } $file_name = date('Y-m-d-his').'-'.$fixed_filename; $import->file_path = $file_name; $import->filesize = null; if (!file_exists($path.'/'.$file_name)) { return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 500); } $import->filesize = filesize($path.'/'.$file_name); $import->save(); $results[] = $import; } $results = (new ImportsTransformer)->transformImports($results); return response()->json([ 'files' => $results, ]); } return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.feature_disabled')), 422); } /** * Processes the specified Import. * * @param int $import_id */ public function process(ItemImportRequest $request, $import_id) : JsonResponse { $this->authorize('import'); // Run a backup immediately before processing if ($request->get('run-backup')) { Log::debug('Backup manually requested via importer'); Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H:i:s')]); } else { Log::debug('NO BACKUP requested via importer'); } $import = Import::find($import_id); if(is_null($import)){ $error[0][0] = trans("validation.exists", ["attribute" => "file"]); return response()->json(Helper::formatStandardApiResponse('import-errors', null, $error), 500); } $errors = $request->import($import); $redirectTo = 'hardware.index'; switch ($request->get('import-type')) { case 'asset': $redirectTo = 'hardware.index'; break; case 'accessory': $redirectTo = 'accessories.index'; break; case 'consumable': $redirectTo = 'consumables.index'; break; case 'component': $redirectTo = 'components.index'; break; case 'license': $redirectTo = 'licenses.index'; break; case 'user': $redirectTo = 'users.index'; break; case 'location': $redirectTo = 'locations.index'; break; } if ($errors) { //Failure return response()->json(Helper::formatStandardApiResponse('import-errors', null, $errors), 500); } //Flash message before the redirect Session::flash('success', trans('admin/hardware/message.import.success')); return response()->json(Helper::formatStandardApiResponse('success', null, ['redirect_url' => route($redirectTo)])); } /** * Remove the specified resource from storage. * * @param int $import_id */ public function destroy($import_id) : JsonResponse { $this->authorize('create', Asset::class); if ($import = Import::find($import_id)) { try { // Try to delete the file Storage::delete('imports/'.$import->file_path); $import->delete(); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.import.file_delete_success'))); } catch (\Exception $e) { // If the file delete didn't work, remove it from the database anyway and return a warning $import->delete(); return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning'))); } } return response()->json(Helper::formatStandardApiResponse('warning', null, trans('admin/hardware/message.import.file_not_deleted_warning'))); } }