UserService::updateLoggedUserPicture()   A
last analyzed

Complexity

Conditions 6
Paths 3

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 14
c 0
b 0
f 0
nc 3
nop 2
dl 0
loc 28
rs 9.2222
1
<?php
2
3
namespace App\Services;
4
5
use App\Constants\TranslationCode;
6
use App\Models\Language;
7
use App\Models\Role;
8
use App\Models\User;
9
use App\Models\UserToken;
10
use Carbon\Carbon;
11
use Illuminate\Contracts\Validation\Validator as ReturnedValidator;
12
use Illuminate\Database\Eloquent\Builder;
13
use Illuminate\Http\Request;
14
use Illuminate\Support\Facades\Auth;
15
use Illuminate\Support\Facades\File;
16
use Illuminate\Support\Facades\Hash;
17
use Illuminate\Support\Facades\Validator;
18
use Illuminate\Support\Str;
19
use IonGhitun\JwtToken\Jwt;
20
use IonGhitun\MysqlEncryption\Models\BaseModel;
21
use Laravel\Socialite\Two\User as SocialiteUser;
22
23
/**
24
 * Class UserService
25
 *
26
 * @package App\Services
27
 */
28
class UserService
29
{
30
    /**
31
     * Validate request on login
32
     *
33
     * @param  Request  $request
34
     *
35
     * @return ReturnedValidator
36
     */
37
    public function validateLoginRequest(Request $request)
38
    {
39
        $rules = [
40
            'email'    => 'required|email|exists_encrypted:users,email',
41
            'password' => 'required'
42
        ];
43
44
        $messages = [
45
            'email.required'         => TranslationCode::ERROR_EMAIL_REQUIRED,
46
            'email.email'            => TranslationCode::ERROR_EMAIL_INVALID,
47
            'email.exists_encrypted' => TranslationCode::ERROR_EMAIL_NOT_REGISTERED,
48
            'password.required'      => TranslationCode::ERROR_PASSWORD_REQUIRED
49
        ];
50
51
        return Validator::make($request->all(), $rules, $messages);
52
    }
53
54
    /**
55
     * Validate request on login with remember token
56
     *
57
     * @param  Request  $request
58
     *
59
     * @return ReturnedValidator
60
     */
61
    public function validateTokenLoginRequest(Request $request)
62
    {
63
        $rules = [
64
            'rememberToken' => 'required'
65
        ];
66
67
        $messages = [
68
            'rememberToken.required' => TranslationCode::ERROR_REMEMBER_TOKEN_REQUIRED
69
        ];
70
71
        return Validator::make($request->all(), $rules, $messages);
72
    }
73
74
    /**
75
     * Get user from email and password
76
     *
77
     * @param  array  $credentials
78
     *
79
     * @return User|null
80
     */
81
    public function loginUser(array $credentials)
82
    {
83
        $builder = self::getUserBuilderForLogin();
84
85
        /** @var User|null $user */
86
        $user = $builder->whereEncrypted('email', $credentials['email'])
87
                        ->first();
88
89
        if (!$user) {
90
            return null;
91
        }
92
93
        $password = $user->password;
94
95
        if (app('hash')->check($credentials['password'], $password)) {
96
            return $user;
97
        }
98
99
        return null;
100
    }
101
102
    /**
103
     * Get user builder for login
104
     *
105
     * @return Builder|BaseModel
106
     */
107
    public static function getUserBuilderForLogin()
108
    {
109
        return User::with([
110
            'role' => function ($query) {
111
                $query->select(['id', 'name'])
112
                      ->with(['permissions']);
113
            }
114
        ]);
115
    }
116
117
    /**
118
     * Generate returned data on login
119
     *
120
     * @param  User  $user
121
     * @param  bool  $remember
122
     *
123
     * @return array
124
     */
125
    public function generateLoginData(User $user, $remember = false)
126
    {
127
        $data = [
128
            'user'  => $user,
129
            'token' => Jwt::generateToken([
130
                'id' => $user->id
131
            ])
132
        ];
133
134
        if ($remember) {
135
            $data['rememberToken'] = $this->generateRememberMeToken($user->id);
136
        }
137
138
        return $data;
139
    }
140
141
    /**
142
     * Generate remember me token
143
     *
144
     * @param $userId
145
     * @param $days
146
     *
147
     * @return string
148
     */
149
    public function generateRememberMeToken($userId, $days = 14)
150
    {
151
        $userToken = new UserToken();
152
153
        $userToken->user_id   = $userId;
154
        $userToken->token     = Str::random(64);
155
        $userToken->type      = UserToken::TYPE_REMEMBER_ME;
156
        $userToken->expire_on = Carbon::now()->addDays($days)->format('Y-m-d H:i:s');
157
158
        $userToken->save();
159
160
        return $userToken->token;
161
    }
162
163
    /**
164
     * Login user with remembered token
165
     *
166
     * @param $token
167
     *
168
     * @return User|null
169
     */
170
    public function loginUserWithRememberToken($token)
171
    {
172
        $builder = self::getUserBuilderForLogin();
173
174
        /** @var User|null $user */
175
        $user = $builder->whereHas('userTokens', function ($query) use ($token) {
176
            $query->where('token', $token)
177
                  ->where('expire_on', '>=', Carbon::now()->format('Y-m-d H:i:s'));
178
        })->first();
179
180
        return $user;
181
    }
182
183
    /**
184
     * Update remember token validity when used on login
185
     *
186
     * @param $token
187
     * @param  int  $days
188
     */
189
    public function updateRememberTokenValability($token, $days = 14)
190
    {
191
        $userToken = UserToken::where('token', $token)
192
                              ->where('type', UserToken::TYPE_REMEMBER_ME)
193
                              ->first();
194
195
        if ($userToken) {
196
            $userToken->expire_on = Carbon::now()->addDays($days)->format('Y-m-d H:i:s');
197
198
            $userToken->save();
199
        }
200
    }
201
202
    /**
203
     * Validate request on facebook login
204
     *
205
     * @param  Request  $request
206
     *
207
     * @return ReturnedValidator
208
     */
209
    public function validateFacebookLoginRequest(Request $request)
210
    {
211
        $rules = [
212
            'facebookId'  => 'required',
213
            'accessToken' => 'required',
214
        ];
215
216
        $messages = [
217
            'facebookId.required'  => TranslationCode::ERROR_FACEBOOK_ID_REQUIRED,
218
            'accessToken.required' => TranslationCode::ERROR_FACEBOOK_ACCESS_TOKEN_REQUIRED
219
        ];
220
221
        return Validator::make($request->all(), $rules, $messages);
222
    }
223
224
    /**
225
     * Validate request on google login
226
     *
227
     * @param  Request  $request
228
     *
229
     * @return ReturnedValidator
230
     */
231
    public function validateGoogleLoginRequest(Request $request)
232
    {
233
        $rules = [
234
            'googleId'    => 'required',
235
            'accessToken' => 'required',
236
        ];
237
238
        $messages = [
239
            'googleId.required'    => TranslationCode::ERROR_GOOGLE_ID_REQUIRED,
240
            'accessToken.required' => TranslationCode::ERROR_GOOGLE_ACCESS_TOKEN_REQUIRED
241
        ];
242
243
        return Validator::make($request->all(), $rules, $messages);
244
    }
245
246
    /**
247
     * Login user with social
248
     *
249
     * @param  SocialiteUser  $socialUser
250
     * @param  Language  $language
251
     * @param  string  $socialId
252
     *
253
     * @return User
254
     */
255
    public function loginUserWithSocial(SocialiteUser $socialUser, Language $language, string $socialId)
256
    {
257
        $builder = self::getUserBuilderForLogin();
258
259
        $user = $builder->where(function ($query) use ($socialUser, $socialId) {
260
            $query->where($socialId, $socialUser->getId())
261
                  ->orWhereEncrypted('email', $socialUser->getEmail());
262
        })->first();
263
264
        if (!$user) {
265
            $user = new User();
266
267
            $user->language_id = $language->id;
268
            $user->name        = $socialUser->getName();
269
            $user->email       = $socialUser->getEmail();
270
271
            if ($socialUser->getAvatar()) {
272
                $baseService = new BaseService();
273
274
                $path = 'uploads/users/';
275
                File::makeDirectory($path, 0777, true, true);
276
277
                $generatedPictureName = time() . '.jpg';
278
279
                $pictureData = $baseService->processImage($path, $socialUser->getAvatar(), $generatedPictureName, true,
280
                    true);
281
282
                if ($pictureData) {
283
                    $user->picture = $pictureData;
284
                }
285
            }
286
        }
287
288
        $user->status    = User::STATUS_CONFIRMED;
289
        $user->$socialId = $socialUser->getId();
290
291
        $user->save();
292
293
        return $user;
294
    }
295
296
    /**
297
     * Validate request on register
298
     *
299
     * @param  Request  $request
300
     *
301
     * @return ReturnedValidator
302
     */
303
    public function validateRegisterRequest(Request $request)
304
    {
305
        $rules = [
306
            'name'           => 'required|name',
307
            'email'          => 'required|email|unique_encrypted:users,email',
308
            'password'       => 'required|min:8|regex:/^.*(?=.{3,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\d\X])(?=.*[^a-zA-Z\d\s:]).*$/',
309
            'retypePassword' => 'required|same:password'
310
        ];
311
312
        $messages = [
313
            'name.required'           => TranslationCode::ERROR_REGISTER_NAME_REQUIRED,
314
            'name.name'               => TranslationCode::ERROR_REGISTER_NAME_NAME,
315
            'email.required'          => TranslationCode::ERROR_REGISTER_EMAIL_REQUIRED,
316
            'email.email'             => TranslationCode::ERROR_REGISTER_EMAIL_INVALID,
317
            'email.unique_encrypted'  => TranslationCode::ERROR_REGISTER_EMAIL_REGISTERED,
318
            'password.required'       => TranslationCode::ERROR_REGISTER_PASSWORD_REQUIRED,
319
            'password.min'            => TranslationCode::ERROR_REGISTER_PASSWORD_MIN8,
320
            'password.regex'          => TranslationCode::ERROR_REGISTER_PASSWORD_COMPLEXITY,
321
            'retypePassword.required' => TranslationCode::ERROR_REGISTER_RETYPE_PASSWORD_REQUIRED,
322
            'retypePassword.same'     => TranslationCode::ERROR_REGISTER_RETYPE_PASSWORD_SAME
323
        ];
324
325
        return Validator::make($request->all(), $rules, $messages);
326
    }
327
328
    /**
329
     * Validate request on update user
330
     *
331
     * @param  Request  $request
332
     *
333
     * @return ReturnedValidator
334
     */
335
    public function validateUpdateUserRequest(Request $request)
336
    {
337
        $rules = [
338
            'name'           => 'required|name',
339
            'email'          => 'required|email',
340
            'oldPassword'    => 'required_with:newPassword',
341
            'newPassword'    => 'nullable|min:8|regex:/^.*(?=.{3,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\d\X])(?=.*[^a-zA-Z\d\s:]).*$/',
342
            'retypePassword' => 'required_with:newPassword|same:newPassword',
343
            'language'       => 'required|exists:languages,code'
344
        ];
345
346
        $messages = [
347
            'name.required'                => TranslationCode::ERROR_UPDATE_NAME_REQUIRED,
348
            'name.name'                    => TranslationCode::ERROR_UPDATE_NAME_NAME,
349
            'email.required'               => TranslationCode::ERROR_UPDATE_EMAIL_REQUIRED,
350
            'email.email'                  => TranslationCode::ERROR_UPDATE_EMAIL_INVALID,
351
            'oldPassword.required_with'    => TranslationCode::ERROR_UPDATE_OLD_PASSWORD_REQUIRED,
352
            'newPassword.min'              => TranslationCode::ERROR_UPDATE_NEW_PASSWORD_MIN8,
353
            'newPassword.regex'            => TranslationCode::ERROR_UPDATE_NEW_PASSWORD_COMPLEXITY,
354
            'retypePassword.required_with' => TranslationCode::ERROR_UPDATE_RETYPE_PASSWORD_REQUIRED,
355
            'retypePassword.same'          => TranslationCode::ERROR_UPDATE_RETYPE_PASSWORD_SAME,
356
            'language.required'            => TranslationCode::ERROR_UPDATE_LANGUAGE_REQUIRED,
357
            'language.exists'              => TranslationCode::ERROR_UPDATE_LANGUAGE_EXISTS,
358
        ];
359
360
        return Validator::make($request->all(), $rules, $messages);
361
    }
362
363
    /**
364
     * Update logged user
365
     *
366
     * @param  User  $user
367
     * @param  Request  $request
368
     * @param  Language  $language
369
     */
370
    public function updateLoggedUser(User &$user, Request $request, Language $language)
371
    {
372
        $email        = $request->get('email');
373
        $confirmEmail = false;
374
375
        if ($user->email !== $email) {
376
            $user->email           = $email;
377
            $user->status          = User::STATUS_EMAIL_UNCONFIRMED;
378
            $user->activation_code = strtoupper(Str::random(6));
379
380
            $confirmEmail = true;
381
        }
382
383
        if ($request->has('newPassword')) {
384
            $user->password = Hash::make($request->get('newPassword'));
385
        }
386
387
        $user->name = $request->get('name');
388
389
        $user->language_id = $language->id;
390
391
        if ($confirmEmail) {
392
            $emailService = new EmailService();
393
394
            $emailService->sendEmailConfirmationCode($user, $language->code);
395
        }
396
397
        $user->save();
398
    }
399
400
    /**
401
     * Validate request on update user picture
402
     *
403
     * @param  Request  $request
404
     *
405
     * @return ReturnedValidator
406
     */
407
    public function validateUpdateUserPictureRequest(Request $request)
408
    {
409
        $rules = [
410
            'picture' => 'required|image',
411
        ];
412
413
        $messages = [
414
            'picture.required' => TranslationCode::ERROR_UPDATE_PICTURE_REQUIRED,
415
            'picture.image'    => TranslationCode::ERROR_UPDATE_PICTURE_IMAGE
416
        ];
417
418
        return Validator::make($request->all(), $rules, $messages);
419
    }
420
421
    /**
422
     * Change logged user picture
423
     *
424
     * @param $user
425
     * @param $picture
426
     */
427
    public function updateLoggedUserPicture(&$user, $picture)
428
    {
429
        /** @var User $user */
430
        $user = Auth::user();
431
432
        $pictureExtension     = $picture->getClientOriginalExtension();
433
        $generatedPictureName = str_replace(' ', '_', $user->name) . '_' . time() . '.' . $pictureExtension;
434
435
        $path = 'uploads/users/';
436
        File::makeDirectory($path, 0777, true, true);
437
438
        $baseService = new BaseService();
439
440
        $pictureData = $baseService->processImage($path, $picture, $generatedPictureName, true);
441
442
        if ($pictureData) {
443
            if ($user->picture) {
444
                foreach ($user->picture as $oldPicture) {
0 ignored issues
show
Bug introduced by
The expression $user->picture of type string is not traversable.
Loading history...
445
                    if ($oldPicture && file_exists($oldPicture)) {
446
                        unlink($oldPicture);
447
                    }
448
                }
449
            }
450
451
            $user->picture = $pictureData;
452
        }
453
454
        $user->save();
455
    }
456
457
    /**
458
     * Validate request on forgot password
459
     *
460
     * @param  Request  $request
461
     *
462
     * @return ReturnedValidator
463
     */
464
    public function validateForgotPasswordRequest(Request $request)
465
    {
466
        $rules = [
467
            'email' => 'required|email|exists_encrypted:users,email'
468
        ];
469
470
        $messages = [
471
            'email.required'         => TranslationCode::ERROR_FORGOT_EMAIL_REQUIRED,
472
            'email.email'            => TranslationCode::ERROR_FORGOT_EMAIL_INVALID,
473
            'email.exists_encrypted' => TranslationCode::ERROR_FORGOT_EMAIL_NOT_REGISTERED
474
        ];
475
476
        return Validator::make($request->all(), $rules, $messages);
477
    }
478
479
    /**
480
     * Send code on email for forgot password
481
     *
482
     * @param  User  $user
483
     * @param  Language  $language
484
     */
485
    public function sendForgotPasswordCode(User $user, Language $language)
486
    {
487
        $user->forgot_code = strtoupper(Str::random(6));
488
        $user->forgot_time = Carbon::now()->format('Y-m-d H:i:s');
489
490
        $emailService = new EmailService();
491
492
        $emailService->sendForgotPasswordCode($user, $language->code);
493
494
        $user->save();
495
    }
496
497
    /**
498
     * Validate request on forgot change password
499
     *
500
     * @param  Request  $request
501
     *
502
     * @return ReturnedValidator
503
     */
504
    public function validateChangePasswordRequest(Request $request)
505
    {
506
        $rules = [
507
            'email'          => 'required|email|exists_encrypted:users,email',
508
            'code'           => 'required',
509
            'password'       => 'required|min:8|regex:/^.*(?=.{3,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\d\X])(?=.*[^a-zA-Z\d\s:]).*$/',
510
            'retypePassword' => 'required|same:password'
511
        ];
512
513
        $messages = [
514
            'email.required'          => TranslationCode::ERROR_FORGOT_EMAIL_REQUIRED,
515
            'email.email'             => TranslationCode::ERROR_FORGOT_EMAIL_INVALID,
516
            'email.exists_encrypted'  => TranslationCode::ERROR_FORGOT_EMAIL_NOT_REGISTERED,
517
            'code.required'           => TranslationCode::ERROR_FORGOT_CODE_REQUIRED,
518
            'password.required'       => TranslationCode::ERROR_FORGOT_PASSWORD_REQUIRED,
519
            'password.min'            => TranslationCode::ERROR_FORGOT_PASSWORD_MIN8,
520
            'password.regex'          => TranslationCode::ERROR_FORGOT_PASSWORD_COMPLEXITY,
521
            'retypePassword.required' => TranslationCode::ERROR_FORGOT_RETYPE_PASSWORD_REQUIRED,
522
            'retypePassword.same'     => TranslationCode::ERROR_FORGOT_RETYPE_PASSWORD_SAME
523
        ];
524
525
        return Validator::make($request->all(), $rules, $messages);
526
    }
527
528
    /**
529
     * Update user password after reset
530
     *
531
     * @param  User  $user
532
     * @param $password
533
     */
534
    public function updatePassword(User $user, $password)
535
    {
536
        $user->forgot_code = null;
537
        $user->forgot_time = null;
538
        $user->password    = Hash::make($password);
539
540
        $user->save();
541
    }
542
543
    /**
544
     * Register user
545
     *
546
     * @param  Request  $request
547
     * @param  Language  $language
548
     */
549
    public function registerUser(Request $request, Language $language)
550
    {
551
        $user = new User();
552
553
        $user->name            = $request->get('name');
554
        $user->email           = $request->get('email');
555
        $user->password        = $request->get('password');
556
        $user->status          = User::STATUS_UNCONFIRMED;
557
        $user->language_id     = $language->id;
558
        $user->role_id         = Role::ID_USER;
559
        $user->activation_code = strtoupper(Str::random(6));
560
561
        $emailService = new EmailService();
562
563
        $emailService->sendActivationCode($user, $language->code);
564
565
        $user->save();
566
    }
567
568
    /**
569
     * Validate activate account
570
     *
571
     * @param  Request  $request
572
     *
573
     * @return ReturnedValidator
574
     */
575
    public function validateActivateAccountOrChangeEmailRequest(Request $request)
576
    {
577
        $rules = [
578
            'email' => 'required|email',
579
            'code'  => 'required'
580
        ];
581
582
        $messages = [
583
            'email.required' => TranslationCode::ERROR_ACTIVATE_EMAIL_REQUIRED,
584
            'email.email'    => TranslationCode::ERROR_ACTIVATE_EMAIL_INVALID,
585
            'code.required'  => TranslationCode::ERROR_ACTIVATE_CODE_REQUIRED
586
        ];
587
588
        return Validator::make($request->all(), $rules, $messages);
589
    }
590
591
    /**
592
     * Activate user account on register or on change email
593
     *
594
     * @param $email
595
     * @param $code
596
     *
597
     * @return bool
598
     */
599
    public function activateUserAccount($email, $code)
600
    {
601
        /** @var User|null $user */
602
        $user = User::whereEncrypted('email', $email)
603
                    ->where('activation_code', $code)
604
                    ->first();
605
606
        if (!$user) {
0 ignored issues
show
introduced by
$user is of type App\Models\User, thus it always evaluated to true.
Loading history...
607
            return false;
608
        }
609
610
        $user->status          = User::STATUS_CONFIRMED;
611
        $user->activation_code = null;
612
613
        $user->save();
614
615
        return true;
616
    }
617
618
    /**
619
     * Validate request on resend
620
     *
621
     * @param  Request  $request
622
     *
623
     * @return ReturnedValidator
624
     */
625
    public function validateResendActivationCodeRequest(Request $request)
626
    {
627
        $rules = [
628
            'email' => 'required|email'
629
        ];
630
631
        $messages = [
632
            'email.required' => TranslationCode::ERROR_ACTIVATE_EMAIL_REQUIRED,
633
            'email.email'    => TranslationCode::ERROR_ACTIVATE_EMAIL_INVALID
634
        ];
635
636
        return Validator::make($request->all(), $rules, $messages);
637
    }
638
639
    /**
640
     * Resend registration mail
641
     *
642
     * @param  Request  $request
643
     *
644
     * @return array|bool
645
     */
646
    public function resendRegisterMail(Request $request)
647
    {
648
        /** @var User|null $user */
649
        $user = User::whereEncrypted('email', $request->get('email'))->first();
650
651
        if (!$user) {
0 ignored issues
show
introduced by
$user is of type App\Models\User, thus it always evaluated to true.
Loading history...
652
            return ['email' => TranslationCode::ERROR_ACTIVATE_EMAIL_NOT_REGISTERED];
653
        }
654
655
        if ($user->status === User::STATUS_CONFIRMED) {
656
            return ['account' => TranslationCode::ERROR_ACTIVATE_ACCOUNT_ACTIVATED];
657
        }
658
659
        if ($user->updated_at->addMinute() > Carbon::now()) {
660
            return ['code' => TranslationCode::ERROR_ACTIVATE_CODE_SEND_COOLDOWN];
661
        }
662
663
        $emailService = new EmailService();
664
665
        $emailService->sendActivationCode($user, $user->language->code);
666
667
        $user->updated_at = Carbon::now()->format('Y-m-d H:i:s');
668
        $user->save();
669
670
        return false;
671
    }
672
}
673