Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
VerificationController
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 3
110
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 verifyByCode
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 1
42
 resend
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace App\Http\Controllers\v1\UserAuth;
4
5use App\Http\Controllers\Controller;
6use App\Http\Models\Auth\EmailValidationTokens;
7use App\Http\Models\Auth\User;
8use App\Http\Services\EmailVerificationService;
9use Illuminate\Auth\Access\AuthorizationException;
10use Illuminate\Foundation\Auth\VerifiesEmails;
11use Illuminate\Http\JsonResponse;
12use Illuminate\Http\Request;
13use Illuminate\Support\Facades\Cache;
14use MongoDB\BSON\UTCDateTime;
15
16class VerificationController extends Controller
17{
18    use VerifiesEmails;
19
20    public function __construct(
21        private readonly EmailVerificationService $emailVerificationService
22    ) {}
23
24    public function verifyByCode(Request $request): JsonResponse
25    {
26        $validation = [
27            'email' => 'required|string|email',
28            'verification_code' => 'required|string',
29        ];
30        $validatedData = $request->validate($validation);
31
32        $user = User::where('email', $validatedData['email'])->first();
33
34        if (!$user) {
35            throw new AuthorizationException;
36        }
37
38        if (!empty($user->email_verified_at)) {
39            return response()->json([
40                'error' => 'Email has already been verified.',
41                'error_type' => 'already_verified',
42            ])->setStatusCode(200);
43        }
44
45        $cacheKey = "verification_code_{$user->id}";
46        $attemptsKey = "verification_attempts_{$user->id}";
47
48        $storedCode = Cache::get($cacheKey);
49        $attempts = Cache::get($attemptsKey, 0);
50
51        if (!$storedCode) {
52            return response()->json([
53                'error' => "Your code has expired.",
54                'error_type' => 'expired_code',
55                'attempts_left' => 0,
56            ], 400);
57        }
58
59        $verification_code = $validatedData['verification_code'];
60
61        if ($attempts >= 5) {
62            Cache::forget($cacheKey);
63            Cache::forget($attemptsKey);
64            return response()->json([
65                'error' => "You've exceeded the number of attempts.",
66                'error_type' => 'expired_code',
67                'attempts_left' => 0,
68            ], 403);
69        }
70
71        $token = EmailValidationTokens::where('email', $validatedData['email'])
72            ->where('used', '!=', true)
73            ->latest()
74            ->first();
75
76        $token->increment('attempts');
77        Cache::increment($attemptsKey);
78
79        if ($verification_code != $storedCode) {
80            return response()->json([
81                'error' => 'Code is invalid or expired.',
82                'error_type' => 'invalid_code',
83                'attempts_left' => 5 - ($attempts + 1),
84            ], 400);
85        }
86
87        Cache::forget($cacheKey);
88        Cache::forget($attemptsKey);
89
90        $token->used = true;
91        $token->save();
92        $user->email_verified_at = new UTCDateTime(now()->getTimestamp() * 1000);
93        $user->save();
94
95        $user->sendWelcomeNotification();
96
97        return response()->json(['message' => 'Email has been verified.']);
98    }
99
100    public function resend(Request $request): JsonResponse
101    {
102        $data = $request->validate([
103            'email' => 'required|string|email',
104        ]);
105
106        $user = User::where('email', $data['email'])->first();
107
108        if (!$user) {
109            throw new AuthorizationException;
110        }
111
112        if (!empty($user->email_verified_at)) {
113            return response()->json([
114                'error' => 'Email has already been verified.',
115                'error_type' => 'already_verified',
116            ])->setStatusCode(200);
117        }
118
119        $this->emailVerificationService->generateToken($data['email']);
120
121        return response()->json(['message' => 'We have e-mailed your verification link!']);
122    }
123}