feat: implement OTP login and password reset functionality with corresponding API endpoints and frontend updates

This commit is contained in:
hamed
2026-06-12 12:54:29 +03:30
parent 8ad983310c
commit 63073c6a42
5 changed files with 753 additions and 102 deletions
+58 -7
View File
@@ -13,9 +13,11 @@ use App\Doctor\Repository\DoctorRepository;
use App\Secretary\Repository\DoctorSecretaryRepository;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
use Doctrine\ORM\EntityManagerInterface;
use OpenApi\Attributes as OA;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\RateLimiter\RateLimiterFactory;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
@@ -25,14 +27,16 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
class AuthController extends BaseController
{
public function __construct(
private readonly UserRepository $userRepo,
private readonly OtpService $otpService,
private readonly TokenService $tokenService,
private readonly RateLimiterFactory $sendCodeLimiter,
private readonly DoctorRepository $doctorRepo,
private readonly ClinicRepository $clinicRepo,
private readonly DoctorSecretaryRepository $secretaryRepo,
private readonly UserRepository $userRepo,
private readonly OtpService $otpService,
private readonly TokenService $tokenService,
private readonly RateLimiterFactory $sendCodeLimiter,
private readonly DoctorRepository $doctorRepo,
private readonly ClinicRepository $clinicRepo,
private readonly DoctorSecretaryRepository $secretaryRepo,
private readonly UserActiveContextRepository $contextRepo,
private readonly UserPasswordHasherInterface $hasher,
private readonly EntityManagerInterface $em,
) {}
/**
@@ -345,6 +349,53 @@ class AuthController extends BaseController
return new JsonResponse($this->tokenService->issueTokens($user));
}
#[Route('/api/v1/user/otp-login', methods: ['POST'])]
public function otpLogin(Request $request): JsonResponse
{
$data = json_decode($request->getContent(), true) ?? [];
$uuid = trim($data['uuid'] ?? '');
if ($uuid === '') {
return $this->error(ErrorCodes::ERR_VALIDATION_002, 'uuid الزامی است', 422);
}
$otpData = $this->otpService->getVerifiedOtpData($uuid);
$user = $this->userRepo->findByMobile($otpData['mobile']);
if (!$user) {
return $this->error(ErrorCodes::ERR_AUTH_005, 'کاربری با این شماره یافت نشد', 401);
}
$this->otpService->deleteOtp($uuid);
return new JsonResponse($this->tokenService->issueTokens($user));
}
#[Route('/api/v1/user/reset-password', methods: ['POST'])]
public function resetPassword(Request $request): JsonResponse
{
$data = json_decode($request->getContent(), true) ?? [];
$uuid = trim($data['uuid'] ?? '');
$newPassword = trim($data['new_password'] ?? '');
if ($uuid === '' || mb_strlen($newPassword) < 6) {
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'uuid و رمز عبور (حداقل ۶ کاراکتر) الزامی است', 422);
}
$otpData = $this->otpService->getVerifiedOtpData($uuid);
$user = $this->userRepo->findByMobile($otpData['mobile']);
if (!$user) {
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'کاربری با این شماره یافت نشد', 404);
}
$user->setPasswordHash($this->hasher->hashPassword($user, $newPassword));
$this->em->flush();
$this->otpService->deleteOtp($uuid);
return $this->success(['message' => 'رمز عبور با موفقیت تغییر یافت']);
}
#[OA\Post(
path: '/oauth/token/refresh',
summary: 'Refresh access token using a refresh token',