99 lines
2.6 KiB
PHP
99 lines
2.6 KiB
PHP
<?php
|
|
|
|
namespace Modules\Auth\Services;
|
|
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Modules\Auth\Entities\EmailVerificationOtp;
|
|
use Modules\Auth\Entities\User;
|
|
use Modules\Auth\Emails\EmailVerificationOtpEmail;
|
|
|
|
class EmailVerificationOtpService
|
|
{
|
|
public function send(User $user): void
|
|
{
|
|
if ($user->hasVerifiedEmail()) {
|
|
return;
|
|
}
|
|
|
|
$otp = $this->generateOtp();
|
|
|
|
EmailVerificationOtp::query()
|
|
->where('user_id', $user->id)
|
|
->delete();
|
|
|
|
EmailVerificationOtp::create([
|
|
'user_id' => $user->id,
|
|
'code' => Hash::make($otp),
|
|
'expires_at' => now()->addMinutes($this->expiryMinutes()),
|
|
'attempts' => 0,
|
|
]);
|
|
|
|
$user->notify(new EmailVerificationOtpEmail($otp));
|
|
}
|
|
|
|
public function verify(User $user, string $otp): void
|
|
{
|
|
if ($user->hasVerifiedEmail()) {
|
|
throw ValidationException::withMessages([
|
|
'email' => ['E-mel anda telah disahkan.'],
|
|
]);
|
|
}
|
|
|
|
$record = EmailVerificationOtp::query()
|
|
->where('user_id', $user->id)
|
|
->latest()
|
|
->first();
|
|
|
|
if (! $record) {
|
|
throw ValidationException::withMessages([
|
|
'otp' => ['Kod OTP tidak dijumpai. Sila minta kod baharu.'],
|
|
]);
|
|
}
|
|
|
|
if ($record->isExpired()) {
|
|
$record->delete();
|
|
|
|
throw ValidationException::withMessages([
|
|
'otp' => ['Kod OTP telah tamat tempoh. Sila minta kod baharu.'],
|
|
]);
|
|
}
|
|
|
|
if ($record->hasExceededMaxAttempts()) {
|
|
$record->delete();
|
|
|
|
throw ValidationException::withMessages([
|
|
'otp' => ['Terlalu banyak percubaan. Sila minta kod baharu.'],
|
|
]);
|
|
}
|
|
|
|
if (! Hash::check($otp, $record->code)) {
|
|
$record->increment('attempts');
|
|
|
|
if ($record->fresh()->hasExceededMaxAttempts()) {
|
|
$record->delete();
|
|
}
|
|
|
|
throw ValidationException::withMessages([
|
|
'otp' => ['Kod OTP tidak sah.'],
|
|
]);
|
|
}
|
|
|
|
$user->forceFill(['email_verified_at' => now()])->save();
|
|
|
|
EmailVerificationOtp::query()
|
|
->where('user_id', $user->id)
|
|
->delete();
|
|
}
|
|
|
|
protected function generateOtp(): string
|
|
{
|
|
return str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
|
|
}
|
|
|
|
protected function expiryMinutes(): int
|
|
{
|
|
return (int) config('auth.email_verification.expiry_minutes', 10);
|
|
}
|
|
}
|