diff --git a/app/Http/Controllers/Api/UploadedFilesController.php b/app/Http/Controllers/Api/UploadedFilesController.php new file mode 100644 index 0000000000..2f6099088f --- /dev/null +++ b/app/Http/Controllers/Api/UploadedFilesController.php @@ -0,0 +1,209 @@ + Accessory::class, + 'assets' => Asset::class, + 'locations' => Location::class, + 'models' => AssetModel::class, + 'users' => User::class, + ]; + + static $map_storage_path = [ + 'accessories' => 'private_uploads/accessories', + 'assets' => 'private_uploads/assets', + 'locations' => 'private_uploads/locations', + 'models' => 'private_uploads/assetmodels', + 'users' => 'private_uploads/users', + ]; + + + + + /** + * List the files for an object. + * + * @since [v7.0.12] + * @author [r-xyz] + */ + public function index(Request $request, $object_type, $id) : JsonResponse | array + { + + $object = self::$map_object_type[$object_type]::find($id); + $this->authorize('view', $object); + + $allowed_columns = + [ + 'id', + 'filename', + 'action_type', + 'note', + 'created_at', + ]; + + $uploads = $object->uploads(); + $offset = ($request->input('offset') > $object->count()) ? $object->count() : abs($request->input('offset')); + $limit = app('api_limit_value'); + $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; + $sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'action_logs.created_at'; + + if ($request->filled('search')) { + + $uploads->where(function ($query) use ($request) { + $query->where('filename', 'LIKE', '%' . $request->input('search') . '%') + ->orWhere('note', 'LIKE', '%' . $request->input('search') . '%'); + }); + } + + $uploads = $uploads->skip($offset)->take($limit)->orderBy($sort, $order)->get(); + return (new UploadedFilesTransformer())->transformFiles($uploads, $uploads->count()); + } + + + /** + * Accepts a POST to upload a file to the server. + * + * @param \App\Http\Requests\UploadFileRequest $request + * @param int $assetModelId + * @since [v7.0.12] + * @author [r-xyz] + */ + public function store(UploadFileRequest $request, $object_type, $id) : JsonResponse + { + + $object = self::$map_object_type[$object_type]::find($id); + $this->authorize('view', $object); + + if ($request->hasFile('file')) { + // If the file storage directory doesn't exist, create it + if (! Storage::exists(self::$map_storage_path[$object_type])) { + Storage::makeDirectory(self::$map_storage_path[$object_type], 775); + } + + // Loop over the attached files and add them to the asset + foreach ($request->file('file') as $file) { + $file_name = $request->handleFile(self::$map_storage_path[$object_type],$object_type.'-'.$object->id, $file); + $files[] = $file_name; + $object->logUpload($file_name, $request->get('notes')); + } + + $files = Actionlog::select('action_logs.*')->where('action_type', '=', 'uploaded') + ->where('item_type', '=', self::$map_object_type[$object_type]) + ->where('item_id', '=', $id)->whereIn('filename', $files) + ->get(); + + return response()->json(Helper::formatStandardApiResponse('success', (new UploadedFilesTransformer())->transformFiles($files, count($files)), trans('admin/hardware/message.upload.success'))); + } + + // No files were submitted + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.upload.nofiles')), 500); + } + + + + /** + * Check for permissions and display the file. + * + * @param AssetModel $model + * @param int $fileId + * @return \Illuminate\Http\JsonResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + * @since [v7.0.12] + * @author [r-xyz] + */ + public function show($object_type, $id, $file_id) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse + { + $object = self::$map_object_type[$object_type]::find($id); + $this->authorize('view', $object); + + // Check that the file being requested exists for the asset + if (! $log = Actionlog::whereNotNull('filename') + ->where('item_type', AssetModel::class) + ->where('item_id', $object->id)->find($file_id)) { + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.no_match', ['id' => $file_id])), 404); + } + + // Form the full filename with path + $file = 'private_uploads/assetmodels/'.$log->filename; + Log::debug('Checking for '.$file); + + // Check the file actually exists on the filesystem + if (! Storage::exists($file)) { + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.download.does_not_exist', ['id' => $file_id])), 404); + } + + if (request('inline') == 'true') { + $headers = [ + 'Content-Disposition' => 'inline', + ]; + return Storage::download($file, $log->filename, $headers); + } + + return StorageHelper::downloader($file); + // Send back an error message + + } + + /** + * Delete the associated file + * + * @param AssetModel $model + * @param int $fileId + * @since [v7.0.12] + * @author [r-xyz] + */ + public function destroy($object_type, $id, $file_id) : JsonResponse + { + + $object = self::$map_object_type[$object_type]::find($id); + $this->authorize('update', $file_id); + + // Check for the file + $log = Actionlog::find($file_id)->where('item_type', AssetModel::class) + ->where('item_id', $object->id)->first(); + + if ($log) { + // Check the file actually exists, and delete it + if (Storage::exists(self::$map_storage_path[$object_type].'/'.$log->filename)) { + Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename); + } + // Delete the record of the file + if ($log->delete()) { + return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.deletefile.success')), 200); + } + + + } + + // The file doesn't seem to really exist, so report an error + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.deletefile.error')), 500); + + } +}