Add image upload to user edit [ch10508] (#7877)

* Use correct Request include

* Updated to use additional form request

* Added SVG sanitizer

* Added response method to form request

* Allow ImageUploadRequest to accept fieldname params, added SVG sanitization, fixed delete

* Fixed upload path for avatars

* Added fieldname variable to blade partial for image upload

* Added enctype="multipart/form-data"  to form to allow uploads

* Added image field

* Updated Request::old() to use $request->old()

* Fixed derp in edit blade referring to $item when it should be $user

* Added svg+xml to image rule
This commit is contained in:
snipe 2020-03-05 18:00:24 -08:00 committed by GitHub
parent 9aed12c5aa
commit 039f5da0e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 25 deletions

View file

@ -5,6 +5,7 @@ use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Controllers\UserNotFoundException;
use App\Http\Requests\SaveUserRequest;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Asset;
use App\Models\Company;
use App\Models\Group;
@ -19,7 +20,7 @@ use Redirect;
use Str;
use Symfony\Component\HttpFoundation\StreamedResponse;
use View;
use Request;
use Illuminate\Http\Request;
/**
@ -65,12 +66,12 @@ class UsersController extends Controller
$userGroups = collect();
if (Request::old('groups')) {
$userGroups = Group::whereIn('id', Request::old('groups'))->pluck('name', 'id');
if ($request->old('groups')) {
$userGroups = Group::whereIn('id', $request->old('groups'))->pluck('name', 'id');
}
$permissions = config('permissions');
$userPermissions = Helper::selectedPermissionsArray($permissions, Request::old('permissions', array()));
$userPermissions = Helper::selectedPermissionsArray($permissions, $request->old('permissions', array()));
$permissions = $this->filterDisplayable($permissions);
$user = new User;
@ -125,6 +126,8 @@ class UsersController extends Controller
}
$user->permissions = json_encode($permissions_array);
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, '', 'avatar', 'avatars');
if ($user->save()) {
if ($request->filled('groups')) {
$user->groups()->sync($request->input('groups'));
@ -201,7 +204,7 @@ class UsersController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(SaveUserRequest $request, $id = null)
public function update(Request $request, $id = null)
{
// We need to reverse the UI specific logic for our
// permissions here before we update the user.
@ -218,6 +221,7 @@ class UsersController extends Controller
try {
$user = User::findOrFail($id);
app('App\Http\Requests\SaveUserRequest');
if ($user->id == $request->input('manager_id')) {
return redirect()->back()->withInput()->with('error', 'You cannot be your own manager.');
@ -291,6 +295,9 @@ class UsersController extends Controller
$user->permissions = json_encode($permissions_array);
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, '', 'avatar', 'avatars');
// Was the user updated?
if ($user->save()) {
// Redirect to the user page

View file

@ -4,6 +4,7 @@ namespace App\Http\Requests;
use App\Models\SnipeModel;
use Intervention\Image\Facades\Image;
use enshrined\svgSanitize\Sanitizer;
use Storage;
class ImageUploadRequest extends Request
@ -26,8 +27,8 @@ class ImageUploadRequest extends Request
public function rules()
{
return [
'image' => 'mimes:png,gif,jpg,jpeg,svg',
'avatar' => 'mimes:png,gif,jpg,jpeg,svg',
'image' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml',
'avatar' => 'mimes:png,gif,jpg,jpeg,svg,bmp,svg+xml',
];
}
@ -42,46 +43,65 @@ class ImageUploadRequest extends Request
* @param String $path location for uploaded images, defaults to uploads/plural of item type.
* @return SnipeModel Target asset is being checked out to.
*/
public function handleImages($item, $w = 550, $path = null)
public function handleImages($item, $w = 550, $fieldname = 'image', $path = null)
{
$type = strtolower(class_basename(get_class($item)));
if(is_null($path)) {
if (is_null($path)) {
$path = str_plural($type);
}
\Log::debug('Image path is: '.$path);
\Log::debug('Image fieldname is: '.$fieldname);
if ($this->hasFile($fieldname)) {
if ($this->hasFile('image')) {
if (!config('app.lock_passwords')) {
if(!Storage::disk('public')->exists($path)) Storage::disk('public')->makeDirectory($path, 775);
if (!Storage::disk('public')->exists($path)) Storage::disk('public')->makeDirectory($path, 775);
$upload = $image = $this->file('image');
$image = $this->file($fieldname);
$ext = $image->getClientOriginalExtension();
$file_name = $type.'-'.str_random(18).'.'.$ext;
if ($image->getClientOriginalExtension()!='svg') {
$upload = Image::make($image->getRealPath())->resize(null, $w, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
// This requires a string instead of an object, so we use ($string)
Storage::disk('public')->put($path.'/'.$file_name, (string)$upload->encode());
// If the file is an SVG, we need to clean it and NOT encode it
} else {
$sanitizer = new Sanitizer();
$dirtySVG = file_get_contents($image->getRealPath());
$cleanSVG = $sanitizer->sanitize($dirtySVG);
Storage::disk('public')->put($path.'/'.$file_name, $cleanSVG);
}
// This requires a string instead of an object, so we use ($string)
Storage::disk('public')->put($path.'/'.$file_name, (string)$upload->encode());
// Remove Current image if exists
if (($item->image) && (file_exists($path.'/'.$item->image))) {
Storage::disk('public')->delete($path.'/'.$file_name);
// Remove current image if it exists and we're uploading a new one
if (($item->{$fieldname}) && (Storage::disk('public')->exists($path.'/'.$item->{$fieldname}))) {
Storage::disk('public')->delete($path.'/'.$item->{$fieldname});
} else {
\Log::debug('Could not delete old file. '.$path.'/'.$item->{$fieldname}.' does not exist?');
}
$item->image = $file_name;
// Assign the new filename as the fieldname
$item->{$fieldname} = $file_name;
}
// If the user isn't uploading anything new but wants to delete their old image, do so
} elseif ($this->input('image_delete')=='1') {
Storage::disk('public')->delete($path.'/'.$item->image);
$item->image = null;
Storage::disk('public')->delete($path.'/'.$item->{$fieldname});
$item->{$fieldname} = null;
}
return $item;
}
}

View file

@ -19,6 +19,12 @@ class SaveUserRequest extends FormRequest
return true;
}
public function response(array $errors)
{
return $this->redirector->back()->withInput()->withErrors($errors, $this->errorBag);
}
/**
* Get the validation rules that apply to the request.
*

View file

@ -76,7 +76,7 @@ class SettingsServiceProvider extends ServiceProvider
// Users
\App::singleton('users_upload_path', function(){
return 'users/';
return 'avatars/';
});
\App::singleton('users_upload_url', function(){

View file

@ -1,9 +1,9 @@
<div class="form-group {{ $errors->has('image') ? 'has-error' : '' }}">
<div class="form-group {{ $errors->has((isset($fieldname) ? $fieldname : 'image')) ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="image">{{ trans('general.image_upload') }}</label>
<div class="col-md-9">
<label class="btn btn-default">
{{ trans('button.select_file') }}
<input type="file" name="image" class="js-uploadFile" id="uploadFile" data-maxsize="{{ \App\Helpers\Helper::file_upload_max_size() }}" accept="image/gif,image/jpeg,image/png,image/svg" style="display:none; max-width: 90%">
<input type="file" name="{{ (isset($fieldname) ? $fieldname : 'image') }}" class="js-uploadFile" id="uploadFile" data-maxsize="{{ \App\Helpers\Helper::file_upload_max_size() }}" accept="image/gif,image/jpeg,image/png,image/svg,image/svg+xml,image/bmp" style="display:none; max-width: 90%">
</label>
<span class='label label-default' id="uploadFile-info"></span>

View file

@ -67,7 +67,7 @@
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form class="form-horizontal" method="post" autocomplete="off" action="{{ (isset($user->id)) ? route('users.update', ['user' => $user->id]) : route('users.store') }}" id="userForm">
<form class="form-horizontal" method="post" autocomplete="off" action="{{ (isset($user->id)) ? route('users.update', ['user' => $user->id]) : route('users.store') }}" enctype="multipart/form-data" id="userForm">
{{csrf_field()}}
@if($user->id)
@ -213,6 +213,22 @@
@include ('partials.forms.edit.company-select', ['translated_name' => trans('general.select_company'), 'fieldname' => 'company_id'])
@endif
<!-- Image -->
@if ($user->avatar)
<div class="form-group {{ $errors->has('image_delete') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="image_delete">{{ trans('general.image_delete') }}</label>
<div class="col-md-5">
{{ Form::checkbox('image_delete') }}
<img src="{{ Storage::disk('public')->url(app('users_upload_path').e($user->avatar)) }}" class="img-responsive" />
{!! $errors->first('image_delete', '<span class="alert-msg"><br>:message</span>') !!}
</div>
</div>
@endif
@include ('partials.forms.edit.image-upload', ['fieldname' => 'avatar'])
<!-- language -->
<div class="form-group {{ $errors->has('locale') ? 'has-error' : '' }}">
<label class="col-md-3 control-label" for="locale">{{ trans('general.language') }}</label>