Skip to content

Commit eb81c29

Browse files
committed
Accessory file upload
Signed-off-by: snipe <[email protected]>
1 parent 2f9e097 commit eb81c29

File tree

6 files changed

+449
-62
lines changed

6 files changed

+449
-62
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Accessories;
4+
5+
use App\Helpers\StorageHelper;
6+
use App\Http\Controllers\Controller;
7+
use App\Http\Requests\AssetFileRequest;
8+
use App\Models\Actionlog;
9+
use App\Models\Accessory;
10+
use Illuminate\Support\Facades\Response;
11+
use Illuminate\Support\Facades\Storage;
12+
use Symfony\Accessory\HttpFoundation\JsonResponse;
13+
use enshrined\svgSanitize\Sanitizer;
14+
15+
class AccessoriesFilesController extends Controller
16+
{
17+
/**
18+
* Validates and stores files associated with a accessory.
19+
*
20+
* @todo Switch to using the AssetFileRequest form request validator.
21+
* @author [A. Gianotto] [<[email protected]>]
22+
* @since [v1.0]
23+
* @param AssetFileRequest $request
24+
* @param int $accessoryId
25+
* @return \Illuminate\Http\RedirectResponse
26+
* @throws \Illuminate\Auth\Access\AuthorizationException
27+
*/
28+
public function store(AssetFileRequest $request, $accessoryId = null)
29+
{
30+
$accessory = Accessory::find($accessoryId);
31+
32+
if (isset($accessory->id)) {
33+
$this->authorize('update', $accessory);
34+
35+
if ($request->hasFile('file')) {
36+
if (! Storage::exists('private_uploads/accessories')) {
37+
Storage::makeDirectory('private_uploads/accessories', 775);
38+
}
39+
40+
foreach ($request->file('file') as $file) {
41+
42+
$extension = $file->getClientOriginalExtension();
43+
$file_name = 'accessory-'.$accessory->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
44+
45+
46+
// Check for SVG and sanitize it
47+
if ($extension == 'svg') {
48+
\Log::debug('This is an SVG');
49+
\Log::debug($file_name);
50+
51+
$sanitizer = new Sanitizer();
52+
$dirtySVG = file_get_contents($file->getRealPath());
53+
$cleanSVG = $sanitizer->sanitize($dirtySVG);
54+
55+
try {
56+
Storage::put('private_uploads/accessories/'.$file_name, $cleanSVG);
57+
} catch (\Exception $e) {
58+
\Log::debug('Upload no workie :( ');
59+
\Log::debug($e);
60+
}
61+
62+
} else {
63+
Storage::put('private_uploads/accessories/'.$file_name, file_get_contents($file));
64+
}
65+
66+
//Log the upload to the log
67+
$accessory->logUpload($file_name, e($request->input('notes')));
68+
}
69+
70+
71+
return redirect()->route('accessories.show', $accessory->id)->with('success', trans('general.file_upload_success'));
72+
73+
}
74+
75+
return redirect()->route('accessories.show', $accessory->id)->with('error', trans('general.no_files_uploaded'));
76+
}
77+
// Prepare the error message
78+
return redirect()->route('accessories.index')
79+
->with('error', trans('general.file_does_not_exist'));
80+
}
81+
82+
/**
83+
* Deletes the selected accessory file.
84+
*
85+
* @author [A. Gianotto] [<[email protected]>]
86+
* @since [v1.0]
87+
* @param int $accessoryId
88+
* @param int $fileId
89+
* @return \Illuminate\Http\RedirectResponse
90+
* @throws \Illuminate\Auth\Access\AuthorizationException
91+
*/
92+
public function destroy($accessoryId = null, $fileId = null)
93+
{
94+
$accessory = Accessory::find($accessoryId);
95+
96+
// the asset is valid
97+
if (isset($accessory->id)) {
98+
$this->authorize('update', $accessory);
99+
$log = Actionlog::find($fileId);
100+
101+
// Remove the file if one exists
102+
if (Storage::exists('accessories/'.$log->filename)) {
103+
try {
104+
Storage::delete('accessories/'.$log->filename);
105+
} catch (\Exception $e) {
106+
\Log::debug($e);
107+
}
108+
}
109+
110+
$log->delete();
111+
112+
return redirect()->back()
113+
->with('success', trans('admin/hardware/message.deletefile.success'));
114+
}
115+
116+
// Redirect to the licence management page
117+
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist'));
118+
}
119+
120+
/**
121+
* Allows the selected file to be viewed.
122+
*
123+
* @author [A. Gianotto] [<[email protected]>]
124+
* @since [v1.4]
125+
* @param int $accessoryId
126+
* @param int $fileId
127+
* @return \Symfony\Accessory\HttpFoundation\Response
128+
* @throws \Illuminate\Auth\Access\AuthorizationException
129+
*/
130+
public function show($accessoryId = null, $fileId = null, $download = true)
131+
{
132+
\Log::debug('Private filesystem is: '.config('filesystems.default'));
133+
$accessory = Accessory::find($accessoryId);
134+
135+
// the accessory is valid
136+
if (isset($accessory->id)) {
137+
$this->authorize('view', $accessory);
138+
$this->authorize('accessories.files', $accessory);
139+
140+
if (! $log = Actionlog::find($fileId)) {
141+
return response('No matching record for that asset/file', 500)
142+
->header('Content-Type', 'text/plain');
143+
}
144+
145+
$file = 'private_uploads/accessories/'.$log->filename;
146+
147+
if (Storage::missing($file)) {
148+
\Log::debug('FILE DOES NOT EXISTS for '.$file);
149+
\Log::debug('URL should be '.Storage::url($file));
150+
151+
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
152+
->header('Content-Type', 'text/plain');
153+
} else {
154+
155+
// We have to override the URL stuff here, since local defaults in Laravel's Flysystem
156+
// won't work, as they're not accessible via the web
157+
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
158+
return StorageHelper::downloader($file);
159+
} else {
160+
if ($download != 'true') {
161+
\Log::debug('display the file');
162+
if ($contents = file_get_contents(Storage::url($file))) { // TODO - this will fail on private S3 files or large public ones
163+
return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file)));
164+
}
165+
166+
return JsonResponse::create(['error' => 'Failed validation: '], 500);
167+
}
168+
169+
return StorageHelper::downloader($file);
170+
171+
}
172+
}
173+
}
174+
175+
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));
176+
}
177+
}

app/Models/Accessory.php

+17
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,23 @@ class Accessory extends SnipeModel
101101

102102

103103

104+
/**
105+
* Establishes the accessories -> action logs -> uploads relationship
106+
*
107+
* @author A. Gianotto <[email protected]>
108+
* @since [v6.1.13]
109+
* @return \Illuminate\Database\Eloquent\Relations\Relation
110+
*/
111+
public function uploads()
112+
{
113+
return $this->hasMany(\App\Models\Actionlog::class, 'item_id')
114+
->where('item_type', '=', self::class)
115+
->where('action_type', '=', 'uploaded')
116+
->whereNotNull('filename')
117+
->orderBy('created_at', 'desc');
118+
}
119+
120+
104121
/**
105122
* Establishes the accessory -> supplier relationship
106123
*

config/permissions.php

+7
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@
145145
'note' => '',
146146
'display' => true,
147147
],
148+
[
149+
'permission' => 'accessories.files',
150+
'label' => 'View and Modify Accessory Files',
151+
'note' => '',
152+
'display' => true,
153+
],
154+
148155
],
149156

150157
'Consumables' => [

0 commit comments

Comments
 (0)