ProfilesController   A
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 494
Duplicated Lines 0 %

Importance

Changes 6
Bugs 1 Features 0
Metric Value
eloc 190
c 6
b 1
f 0
dl 0
loc 494
rs 9.52
wmc 36

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A validator() 0 4 1
A profile_validator() 0 12 1
A show() 0 16 2
A getUserByUsername() 0 3 1
A edit() 0 24 2
A getIdMultiKey() 0 3 1
A upload() 0 23 2
B update() 0 60 7
A updateUserPassword() 0 35 3
A account() 0 10 1
A userProfileAvatar() 0 3 1
A sendGoodbyEmail() 0 3 1
A getSeperationKey() 0 3 1
A deleteUserAccount() 0 54 3
A updateUserAccount() 0 41 5
A uploadBackground() 0 24 2
A userProfileBackgroundImage() 0 3 1
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,
175
                $profile_validator
176
            );
177
178
            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...
179
        }
180
181
        if ($user->profile == null) {
182
            $profile = new Profile();
183
            $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...
184
            $user->profile()->save($profile);
185
        } else {
186
            if ($request->ajax()) {
187
                $user->profile->fill($convertedData)->save();
188
                $user->fill($convertedData);
189
            } else {
190
                $user->profile->fill($input)->save();
191
                $user->fill($input);
192
            }
193
        }
194
195
        $user->updated_ip_address = $ipAddress->getClientIp();
196
        $user->save();
197
198
        if ($request->ajax()) {
199
            $theme = Theme::find($user->profile->theme_id);
200
201
            $returnData = [
202
                'title'     => trans('auth.success'),
203
                'message'   => trans('profile.updateSuccess'),
204
                'themeLink' => $theme->link,
205
            ];
206
207
            return response()->json($returnData, 200);
208
        }
209
210
        return redirect('profile/'.$user->name.'/edit')->with('success', trans('profile.updateSuccess'));
211
    }
212
213
    /**
214
     * User account admin page.
215
     *
216
     * @return \Illuminate\Http\Response
217
     */
218
    public function account()
219
    {
220
        $user = \Auth::user();
221
        $username = $user->name;
0 ignored issues
show
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...
Unused Code introduced by
The assignment to $username is dead and can be removed.
Loading history...
222
223
        $data = [
224
            'user' => $user,
225
        ];
226
227
        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...
228
    }
229
230
    /**
231
     * Update the specified resource in storage.
232
     *
233
     * @param \Illuminate\Http\Request $request
234
     * @param int                      $id
235
     *
236
     * @return \Illuminate\Http\Response
237
     */
238
    public function updateUserAccount(Request $request, $id)
239
    {
240
        $currentUser = \Auth::user();
0 ignored issues
show
Unused Code introduced by
The assignment to $currentUser is dead and can be removed.
Loading history...
241
        $user = User::findOrFail($id);
242
        $emailCheck = ($request->input('email') != '') && ($request->input('email') != $user->email);
243
        $ipAddress = new CaptureIpTrait();
244
245
        $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...
246
            'name'      => 'required|max:255',
247
        ]);
248
249
        $rules = [];
250
251
        if ($emailCheck) {
252
            $rules = [
253
                'email'     => 'email|max:255|unique:users',
254
            ];
255
        }
256
257
        $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

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