Completed
Push — master ( 8287d1...42f9a1 )
by Jeremy
05:54
created

ProfilesController::update()   B

Complexity

Conditions 7
Paths 28

Size

Total Lines 59
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
cc 7
eloc 38
c 4
b 1
f 0
nc 28
nop 2
dl 0
loc 59
rs 8.3786

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace App\Http\Controllers;
4
5
use App\Models\Profile;
6
use App\Models\Theme;
7
use App\Models\User;
8
use App\Notifications\SendGoodbyeEmail;
9
use App\Traits\CaptureIpTrait;
10
use File;
11
use Illuminate\Database\Eloquent\ModelNotFoundException;
12
use Illuminate\Http\Request;
13
use Illuminate\Support\Facades\Input;
14
use Illuminate\Support\Facades\Session;
15
use Image;
16
use Validator;
17
use View;
18
use Webpatser\Uuid\Uuid;
19
20
class ProfilesController extends Controller
21
{
22
    protected $idMultiKey = '618423'; //int
23
    protected $seperationKey = '****';
24
25
    /**
26
     * Create a new controller instance.
27
     *
28
     * @return void
29
     */
30
    public function __construct()
31
    {
32
        $this->middleware('auth');
33
    }
34
35
    /**
36
     * Get a validator for an incoming registration request.
37
     *
38
     * @param array $data
39
     *
40
     * @return \Illuminate\Contracts\Validation\Validator
41
     */
42
    public function profile_validator(array $data)
43
    {
44
        return Validator::make($data, [
45
            'first_name'        => 'nullable|alpha',
46
            'last_name'         => 'nullable|alpha',
47
            'theme_id'          => 'required',
48
            'location'          => 'nullable',
49
            'bio'               => 'nullable|max:500',
50
            'twitter_username'  => 'nullable|max:50',
51
            'github_username'   => 'nullable|max:50',
52
            'avatar'            => '',
53
            'avatar_status'     => '',
54
        ]);
55
    }
56
57
    /**
58
     * Get a validator for an incoming update user request.
59
     *
60
     * @param array $data
61
     *
62
     * @return \Illuminate\Contracts\Validation\Validator
63
     */
64
    public function validator(array $data)
65
    {
66
        return Validator::make($data, [
67
            'name'              => 'required|max:255',
68
        ]);
69
    }
70
71
    /**
72
     * Fetch user
73
     * (You can extract this to repository method).
74
     *
75
     * @param $username
76
     *
77
     * @return mixed
78
     */
79
    public function getUserByUsername($username)
80
    {
81
        return User::with('profile')->wherename($username)->firstOrFail();
82
    }
83
84
    /**
85
     * Display the specified resource.
86
     *
87
     * @param string $username
88
     *
89
     * @return Response
0 ignored issues
show
Bug introduced by
The type App\Http\Controllers\Response was not found. Did you mean Response? If so, make sure to prefix the type with \.
Loading history...
90
     */
91
    public function show($username)
92
    {
93
        try {
94
            $user = $this->getUserByUsername($username);
95
        } catch (ModelNotFoundException $exception) {
96
            abort(404);
97
        }
98
99
        $currentTheme = Theme::find($user->profile->theme_id);
100
101
        $data = [
102
            'user'         => $user,
103
            'currentTheme' => $currentTheme,
104
        ];
105
106
        return view('profiles.show')->with($data);
0 ignored issues
show
Bug Best Practice introduced by
The expression return view('profiles.show')->with($data) returns the type Illuminate\View\View which is incompatible with the documented return type App\Http\Controllers\Response.
Loading history...
107
    }
108
109
    /**
110
     * /profiles/username/edit.
111
     *
112
     * @param $username
113
     *
114
     * @return mixed
115
     */
116
    public function edit($username)
117
    {
118
        try {
119
            $user = $this->getUserByUsername($username);
120
        } catch (ModelNotFoundException $exception) {
121
            return view('pages.status')
122
                ->with('error', trans('profile.notYourProfile'))
123
                ->with('error_title', trans('profile.notYourProfileTitle'));
124
        }
125
126
        $themes = Theme::where('status', 1)
127
                       ->orderBy('name', 'asc')
128
                       ->get();
129
130
        $currentTheme = Theme::find($user->profile->theme_id);
131
132
        $data = [
133
            'user'          => $user,
134
            'themes'        => $themes,
135
            'currentTheme'  => $currentTheme,
136
137
        ];
138
139
        return view('profiles.edit')->with($data);
140
    }
141
142
    /**
143
     * Update a user's profile.
144
     *
145
     * @param $username
146
     *
147
     * @throws Laracasts\Validation\FormValidationException
148
     *
149
     * @return mixed
150
     */
151
    public function update($username, Request $request)
152
    {
153
        $data = $request->formData;
154
        $info = [];
155
        foreach ($data as $key => $value) {
156
            $info[] = [
157
                $value['name'] => $value['value'],
158
            ];
159
        }
160
        $convertedData = call_user_func_array('array_merge', $info);
161
162
        $user = $this->getUserByUsername($username);
163
        $ipAddress = new CaptureIpTrait();
164
165
        if ($request->ajax()) {
166
            $profile_validator = $this->profile_validator($convertedData);
167
        } else {
168
            $profile_validator = $this->profile_validator($request->all());
169
            $input = $request->all();
170
        }
171
172
        if ($profile_validator->fails()) {
173
            $this->throwValidationException(
0 ignored issues
show
Bug introduced by
The method throwValidationException() does not exist on App\Http\Controllers\ProfilesController. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

173
            $this->/** @scrutinizer ignore-call */ 
174
                   throwValidationException(
Loading history...
174
                $request, $profile_validator
175
            );
176
177
            return redirect('profile/'.$user->name.'/edit')->withErrors($validator)->withInput();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $validator does not exist. Did you maybe mean $profile_validator?
Loading history...
178
        }
179
180
        if ($user->profile == null) {
181
            $profile = new Profile();
182
            $profile->fill($input);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $input does not seem to be defined for all execution paths leading up to this point.
Loading history...
183
            $user->profile()->save($profile);
184
        } else {
185
            if ($request->ajax()) {
186
                $user->profile->fill($convertedData)->save();
187
                $user->fill($convertedData);
188
            } else {
189
                $user->profile->fill($input)->save();
190
                $user->fill($input);
191
            }
192
        }
193
194
        $user->updated_ip_address = $ipAddress->getClientIp();
195
        $user->save();
196
197
        if ($request->ajax()) {
198
            $theme = Theme::find($user->profile->theme_id);
199
200
            $returnData = [
201
                'title'     => trans('auth.success'),
202
                'message'   => trans('profile.updateSuccess'),
203
                'themeLink' => $theme->link,
204
            ];
205
206
            return response()->json($returnData, 200);
207
        }
208
209
        return redirect('profile/'.$user->name.'/edit')->with('success', trans('profile.updateSuccess'));
210
    }
211
212
    /**
213
     * User account admin page.
214
     *
215
     * @return \Illuminate\Http\Response
216
     */
217
    public function account()
218
    {
219
        $user = \Auth::user();
220
        $username = $user->name;
0 ignored issues
show
Unused Code introduced by
The assignment to $username is dead and can be removed.
Loading history...
Bug introduced by
Accessing name on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
221
222
        $data = [
223
            'user' => $user,
224
        ];
225
226
        return view('profiles.account')->with($data);
0 ignored issues
show
Bug Best Practice introduced by
The expression return view('profiles.account')->with($data) returns the type Illuminate\View\View which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
227
    }
228
229
    /**
230
     * Update the specified resource in storage.
231
     *
232
     * @param \Illuminate\Http\Request $request
233
     * @param int                      $id
234
     *
235
     * @return \Illuminate\Http\Response
236
     */
237
    public function updateUserAccount(Request $request, $id)
238
    {
239
        $currentUser = \Auth::user();
0 ignored issues
show
Unused Code introduced by
The assignment to $currentUser is dead and can be removed.
Loading history...
240
        $user = User::findOrFail($id);
241
        $emailCheck = ($request->input('email') != '') && ($request->input('email') != $user->email);
242
        $ipAddress = new CaptureIpTrait();
243
244
        $validator = Validator::make($request->all(), [
0 ignored issues
show
Unused Code introduced by
The assignment to $validator is dead and can be removed.
Loading history...
245
            'name'      => 'required|max:255',
246
        ]);
247
248
        $rules = [];
249
250
        if ($emailCheck) {
251
            $rules = [
252
                'email'     => 'email|max:255|unique:users',
253
            ];
254
        }
255
256
        $validator = $this->validator($request->all(), $rules);
0 ignored issues
show
Unused Code introduced by
The call to App\Http\Controllers\Pro...Controller::validator() has too many arguments starting with $rules. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

256
        /** @scrutinizer ignore-call */ 
257
        $validator = $this->validator($request->all(), $rules);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
257
258
        if ($validator->fails()) {
259
            $this->throwValidationException(
260
                $request, $validator
261
            );
262
        }
263
264
        $user->name = $request->input('name');
265
        $user->first_name = $request->input('first_name');
266
        $user->last_name = $request->input('last_name');
267
268
        if ($emailCheck) {
269
            $user->email = $request->input('email');
270
        }
271
272
        $user->updated_ip_address = $ipAddress->getClientIp();
273
274
        $user->save();
275
276
        return redirect('profile/'.$user->name.'/edit')->with('success', trans('profile.updateAccountSuccess'));
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect('profile...updateAccountSuccess')) returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
277
    }
278
279
    /**
280
     * Update the specified resource in storage.
281
     *
282
     * @param \Illuminate\Http\Request $request
283
     * @param int                      $id
284
     *
285
     * @return \Illuminate\Http\Response
286
     */
287
    public function updateUserPassword(Request $request, $id)
288
    {
289
        $currentUser = \Auth::user();
0 ignored issues
show
Unused Code introduced by
The assignment to $currentUser is dead and can be removed.
Loading history...
290
        $user = User::findOrFail($id);
291
        $ipAddress = new CaptureIpTrait();
292
293
        $validator = Validator::make($request->all(),
294
            [
295
                'password'              => 'required|min:6|max:20|confirmed',
296
                'password_confirmation' => 'required|same:password',
297
            ],
298
            [
299
                'password.required'     => trans('auth.passwordRequired'),
300
                'password.min'          => trans('auth.PasswordMin'),
301
                'password.max'          => trans('auth.PasswordMax'),
302
            ]
303
        );
304
305
        if ($validator->fails()) {
306
            $this->throwValidationException(
307
                $request, $validator
308
            );
309
        }
310
311
        if ($request->input('password') != null) {
312
            $user->password = bcrypt($request->input('password'));
313
        }
314
315
        $user->updated_ip_address = $ipAddress->getClientIp();
316
317
        $user->save();
318
319
        return redirect('profile/'.$user->name.'/edit')->with('success', trans('profile.updatePWSuccess'));
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect('profile...file.updatePWSuccess')) returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
320
    }
321
322
    /**
323
     * Upload and Update user avatar.
324
     *
325
     * @param $file
326
     *
327
     * @return mixed
328
     */
329
    public function upload()
330
    {
331
        if (Input::hasFile('file')) {
332
            $currentUser = \Auth::user();
333
            $avatar = Input::file('file');
334
            $filename = 'avatar.'.$avatar->getClientOriginalExtension();
335
            $save_path = storage_path().'/users/id/'.$currentUser->id.'/uploads/images/avatar/';
0 ignored issues
show
Bug introduced by
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
336
            $path = $save_path.$filename;
337
            $public_path = '/images/profile/'.$currentUser->id.'/avatar/'.$filename;
338
339
            // Make the user a folder and set permissions
340
            File::makeDirectory($save_path, $mode = 0755, true, true);
341
342
            // Save the file to the server
343
            Image::make($avatar)->resize(300, 300)->save($save_path.$filename);
344
345
            // Save the public image path
346
            $currentUser->profile->avatar = $public_path;
0 ignored issues
show
Bug introduced by
Accessing profile on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
347
            $currentUser->profile->save();
348
349
            return response()->json(['path'=> $path], 200);
350
        } else {
351
            return response()->json(false, 200);
352
        }
353
    }
354
355
    /**
356
     * Upload and update the user profile background.
357
     *
358
     * @param $file
359
     *
360
     * @return mixed
361
     */
362
    public function uploadBackground()
363
    {
364
        if (Input::hasFile('file')) {
365
            $currentUser = \Auth::user();
366
            $user_profile_bg = Input::file('file');
367
            $filename = 'background.'.$user_profile_bg->getClientOriginalExtension();
368
            $save_path = storage_path().'/users/id/'.$currentUser->id.'/uploads/images/background/';
0 ignored issues
show
Bug introduced by
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
369
            $path = $save_path.$filename;
370
            $public_path = '/images/profile/'.$currentUser->id.'/background/'.$filename;
371
372
            // Make the user a folder and set permissions
373
            File::makeDirectory($save_path, $mode = 0755, true, true);
374
375
            // Save the file to the server
376
            // Image::make($user_profile_bg)->resize(300, 300)->save($save_path . $filename);
377
            Image::make($user_profile_bg)->save($save_path.$filename);
378
379
            // Save the public image path
380
            $currentUser->profile->user_profile_bg = $public_path;
0 ignored issues
show
Bug introduced by
Accessing profile on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
381
            $currentUser->profile->save();
382
383
            return response()->json(['path'=> $path], 200);
384
        } else {
385
            return response()->json(false, 200);
386
        }
387
    }
388
389
    /**
390
     * Show user avatar.
391
     *
392
     * @param $id
393
     * @param $image
394
     *
395
     * @return string
396
     */
397
    public function userProfileAvatar($id, $image)
398
    {
399
        return Image::make(storage_path().'/users/id/'.$id.'/uploads/images/avatar/'.$image)->response();
400
    }
401
402
    /**
403
     * Show user background image.
404
     *
405
     * @param $id
406
     * @param $image
407
     *
408
     * @return string
409
     */
410
    public function userProfileBackgroundImage($id, $image)
411
    {
412
        return Image::make(storage_path().'/users/id/'.$id.'/uploads/images/background/'.$image)->response();
413
    }
414
415
    /**
416
     * Update the specified resource in storage.
417
     *
418
     * @param \Illuminate\Http\Request $request
419
     * @param int                      $id
420
     *
421
     * @return \Illuminate\Http\Response
422
     */
423
    public function deleteUserAccount(Request $request, $id)
424
    {
425
        $currentUser = \Auth::user();
426
        $user = User::findOrFail($id);
427
        $ipAddress = new CaptureIpTrait();
428
429
        $validator = Validator::make($request->all(),
430
            [
431
                'checkConfirmDelete'            => 'required',
432
            ],
433
            [
434
                'checkConfirmDelete.required'   => trans('profile.confirmDeleteRequired'),
435
            ]
436
        );
437
438
        if ($validator->fails()) {
439
            $this->throwValidationException(
440
                $request, $validator
441
            );
442
        }
443
444
        if ($user->id != $currentUser->id) {
0 ignored issues
show
Bug introduced by
Accessing id on the interface Illuminate\Contracts\Auth\Authenticatable suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
445
            return redirect('profile/'.$user->name.'/edit')->with('error', trans('profile.errorDeleteNotYour'));
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect('profile...e.errorDeleteNotYour')) returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
446
        }
447
448
        // Create and encrypt user account restore token
449
        $sepKey = $this->getSeperationKey();
450
        $userIdKey = $this->getIdMultiKey();
451
        $restoreKey = config('settings.restoreKey');
452
        $encrypter = config('settings.restoreUserEncType');
453
        $level1 = $user->id * $userIdKey;
454
        $level2 = urlencode(Uuid::generate(4).$sepKey.$level1);
455
        $level3 = base64_encode($level2);
456
        $level4 = openssl_encrypt($level3, $encrypter, $restoreKey);
457
        $level5 = base64_encode($level4);
458
459
        // Save Restore Token and Ip Address
460
        $user->token = $level5;
461
        $user->deleted_ip_address = $ipAddress->getClientIp();
462
        $user->save();
463
464
        // Send Goodbye email notification
465
        $this->sendGoodbyEmail($user, $user->token);
466
467
        // Soft Delete User
468
        $user->delete();
469
470
        // Clear out the session
471
        $request->session()->flush();
472
        $request->session()->regenerate();
473
474
        return redirect('/login/')->with('success', trans('profile.successUserAccountDeleted'));
0 ignored issues
show
Bug Best Practice introduced by
The expression return redirect('/login/...ssUserAccountDeleted')) returns the type Illuminate\Http\RedirectResponse which is incompatible with the documented return type Illuminate\Http\Response.
Loading history...
475
    }
476
477
    /**
478
     * Send GoodBye Email Function via Notify.
479
     *
480
     * @param array  $user
481
     * @param string $token
482
     *
483
     * @return void
484
     */
485
    public static function sendGoodbyEmail(User $user, $token)
486
    {
487
        $user->notify(new SendGoodbyeEmail($token));
488
    }
489
490
    /**
491
     * Get User Restore ID Multiplication Key.
492
     *
493
     * @return string
494
     */
495
    public function getIdMultiKey()
496
    {
497
        return $this->idMultiKey;
498
    }
499
500
    /**
501
     * Get User Restore Seperation Key.
502
     *
503
     * @return string
504
     */
505
    public function getSeperationKey()
506
    {
507
        return $this->seperationKey;
508
    }
509
}
510