Skip to content

Commit 58d1edf

Browse files
email_verification
1 parent 0b8d7e9 commit 58d1edf

File tree

10 files changed

+199
-6
lines changed

10 files changed

+199
-6
lines changed

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
```bash
3030
composer install
3131
php artisan key:generate
32-
3332
```
3433
4- Run database migrations
3534

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Api\Auth;
4+
5+
use App\Traits\ApiTrait;
6+
use Illuminate\Http\Request;
7+
use App\Http\Controllers\Controller;
8+
use Illuminate\Support\Facades\Auth;
9+
use App\Http\Requests\Auth\CodeRequest;
10+
use App\Mail\VerificationCode;
11+
use App\Models\User;
12+
use Illuminate\Support\Facades\Mail;
13+
14+
class EmailVerificationController extends Controller
15+
{
16+
public function send(Request $request)
17+
{
18+
$user = Auth::guard('sanctum')->user();
19+
$token = $request->header('Authorization');
20+
$code = rand(1000, 9999); // Generate a 4-digit code
21+
$user->code = $code;
22+
$user->code_expired_at = now()->addMinutes(config('auth.code_timeout'));
23+
$user->save();
24+
25+
try {
26+
Mail::to($user)->send(new VerificationCode($user));
27+
} catch (\Exception $e) {
28+
return ApiTrait::errorMessage(['mail' => $e->getMessage()], 'Please Try Again Later');
29+
}
30+
31+
// Remove "Bearer" prefix from token
32+
$token = str_replace('Bearer ', '', $token);
33+
34+
$user->token = $token;
35+
36+
return ApiTrait::data(['data' => ['user' => $user]], "Mail Sent Successfully", 200);
37+
}
38+
39+
public function verify(CodeRequest $request)
40+
{
41+
$user = Auth::guard('sanctum')->user();
42+
$token = $request->header('Authorization');
43+
$now = now();
44+
45+
if ($user->code != $request->code) {
46+
return ApiTrait::errorMessage(['code' => 'Wrong Code'], "Invalid Code", 422);
47+
}
48+
49+
if ($now > $user->code_expired_at) {
50+
return ApiTrait::errorMessage(['code' => 'Expired Code'], "Invalid Code", 422);
51+
}
52+
53+
$user->email_verified_at = $now;
54+
$user->save();
55+
$token = str_replace('Bearer ', '', $token);
56+
57+
$user->token = $token;
58+
59+
return ApiTrait::data(['data' => ['user' => $user]], "Correct Code", 200);
60+
}
61+
}
62+
63+
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
namespace App\Http\Requests\Auth;
4+
5+
use Illuminate\Foundation\Http\FormRequest;
6+
7+
class CodeRequest extends FormRequest
8+
{
9+
/**
10+
* Determine if the user is authorized to make this request.
11+
*
12+
* @return bool
13+
*/
14+
public function authorize()
15+
{
16+
return true;
17+
}
18+
19+
/**
20+
* Get the validation rules that apply to the request.
21+
*
22+
* @return array<string, mixed>
23+
*/
24+
public function rules()
25+
{
26+
return [
27+
'code'=>['required','numeric','digits:4','exists:users']
28+
];
29+
}
30+
}

app/Mail/VerificationCode.php

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace App\Mail;
4+
5+
use App\Models\User;
6+
use Illuminate\Bus\Queueable;
7+
use Illuminate\Contracts\Queue\ShouldQueue;
8+
use Illuminate\Mail\Mailable;
9+
use Illuminate\Mail\Mailables\Address;
10+
use Illuminate\Mail\Mailables\Content;
11+
use Illuminate\Mail\Mailables\Envelope;
12+
use Illuminate\Queue\SerializesModels;
13+
14+
class VerificationCode extends Mailable
15+
{
16+
use Queueable, SerializesModels;
17+
18+
/**
19+
* Create a new message instance.
20+
*
21+
* @return void
22+
*/
23+
public function __construct(public User $user)
24+
{
25+
26+
}
27+
28+
/**
29+
* Get the message envelope.
30+
*
31+
* @return \Illuminate\Mail\Mailables\Envelope
32+
*/
33+
public function envelope()
34+
{
35+
return new Envelope(
36+
from: new Address('[email protected]', 'CodeLink Support'),
37+
subject: 'CodeLink | Verification Code',
38+
);
39+
}
40+
41+
/**
42+
* Get the message content definition.
43+
*
44+
* @return \Illuminate\Mail\Mailables\Content
45+
*/
46+
public function content()
47+
{
48+
return new Content(
49+
view: 'mails.VerificationCode',
50+
);
51+
}
52+
53+
/**
54+
* Get the attachments for the message.
55+
*
56+
* @return array
57+
*/
58+
public function attachments()
59+
{
60+
return [];
61+
}
62+
}

app/Traits/ApiTrait.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ trait ApiTrait{
77
public static function successMessage(string $message="",int $statusCode = 200)
88
{
99
return response()->json([
10-
'success'=>true,
10+
'result'=>true,
1111
'message'=>$message,
1212
'data'=>(object)[],
1313
'errors'=>(object)[]
@@ -17,7 +17,7 @@ public static function successMessage(string $message="",int $statusCode = 200)
1717
public static function errorMessage(array $errors,string$message="",int $statusCode = 422)
1818
{
1919
return response()->json([
20-
'success'=>false,
20+
'result'=>false,
2121
'message'=>$message,
2222
'data'=>(object)[],
2323
'errors'=>(object)$errors
@@ -28,7 +28,7 @@ public static function errorMessage(array $errors,string$message="",int $statusC
2828
public static function data(array $data,string $message = "",int $statusCode = 200)
2929
{
3030
return response()->json([
31-
'success'=>true,
31+
'result'=>true,
3232
'message'=>$message,
3333
'data'=>(object)$data,
3434
'errors'=>(object)[]

config/auth.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,5 @@
107107
*/
108108

109109
'password_timeout' => 10800,
110-
110+
'code_timeout'=>600
111111
];

config/sanctum.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
|
2727
| This array contains the authentication guards that will be checked when
2828
| Sanctum is trying to authenticate a request. If none of these guards
29-
| are able to authenticate the request, Sanctum will use the bearer
29+
| are able to authenticate the request, Sanctum will use the er
3030
| token that's present on an incoming request for authentication.
3131
|
3232
*/

database/migrations/2014_10_12_000000_create_users_table.php

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public function up()
1717
$table->id();
1818
$table->string('name');
1919
$table->string('email')->unique();
20+
$table->integer('code')->nullable();
21+
$table->timestamp('code_expired_at')->nullable();
2022
$table->timestamp('email_verified_at')->nullable();
2123
$table->string('password');
2224
$table->rememberToken();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE html>
2+
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>CodeLink | Verification Code</title>
8+
</head>
9+
10+
<body style="margin: 0; padding: 0; font-family: Arial, sans-serif; background-color: #f4f4f4;">
11+
12+
<div style="max-width: 600px; margin: 0 auto; padding: 20px; background-color: #ffffff;">
13+
14+
<h3 style="font-size: 24px; color: #333;">Hello {{ $user->name }},</h3>
15+
16+
<p style="font-size: 16px; color: #666;">Your Verification Code: <strong>{{ $user->code }}</strong></p>
17+
18+
<p style="font-size: 16px; color: #666;">
19+
It will expire after {{ config('auth.code_timeout')/60 }} minutes</strong>
20+
</p>
21+
22+
<p style="font-size: 16px; color: #666;">Thank you!</p>
23+
24+
</div>
25+
26+
</body>
27+
28+
</html>

routes/api.php

+9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
use Illuminate\Support\Facades\Route;
55
use App\Http\Controllers\Api\Auth\LoginController;
66
use App\Http\Controllers\Api\Auth\SignupController;
7+
use App\Http\Controllers\Api\Auth\ResetPasswordController;
8+
use App\Http\Controllers\Api\Auth\EmailVerificationController;
79

810
/*
911
|--------------------------------------------------------------------------
@@ -20,9 +22,16 @@
2022
return $request->user();
2123
});
2224

25+
2326
Route::prefix('user')->group(function () {
2427
Route::post('/signup', SignupController::class); // guest
2528

29+
Route::group(['controller' => EmailVerificationController::class, 'middleware' => 'auth:sanctum'], function () {
30+
Route::get('/send-mail', 'send'); //auth
31+
Route::post('/check-code', 'verify'); //auth
32+
});
33+
34+
2635
Route::controller(LoginController::class)->group(function () {
2736
Route::middleware('auth:sanctum')->group(function () {
2837
Route::get('/logout', 'logout'); //auth

0 commit comments

Comments
 (0)