diff --git a/server/src/infrastructure/services/JoiService.ts b/server/src/infrastructure/services/JoiService.ts index 31cdcb75..2411f78b 100644 --- a/server/src/infrastructure/services/JoiService.ts +++ b/server/src/infrastructure/services/JoiService.ts @@ -45,7 +45,7 @@ export default class JoiService implements IValidatorService { } public validatePhoneNumber(phoneNumber: string): boolean { - const schema = Joi.string().pattern(new RegExp("^[0-9]{10}$")); + const schema = Joi.string().min(4).max(15); const { error } = schema.validate(phoneNumber); if (error) { throw new ValidationError('Invalid phone number format', StatusCode.BadRequest); diff --git a/server/src/presentation/controllers/doctor/AuthenticationController.ts b/server/src/presentation/controllers/doctor/AuthenticationController.ts index 9756b024..34b8e7a3 100644 --- a/server/src/presentation/controllers/doctor/AuthenticationController.ts +++ b/server/src/presentation/controllers/doctor/AuthenticationController.ts @@ -10,14 +10,6 @@ export default class AuthDoctorController { async signin(req: Request, res: Response, next: NextFunction) { try { const { email, password } = req.body; - - if (!email.trim()) { - return res.status(StatusCode.BadRequest).json({ message: "Email is required" }); - } - if (!password.trim()) { - return res.status(StatusCode.BadRequest).json({ message: "Password is required" }); - } - await this.authDoctorUseCase.signin(email, password); res.status(StatusCode.Success).json({ message: "OTP has been sent to your email" }); } catch (error: any) { @@ -27,9 +19,7 @@ export default class AuthDoctorController { async validateOtp(req: Request, res: Response, next: NextFunction) { try { const { otp, email } = req.body; - if (!otp) return res.status(StatusCode.BadRequest).json({ message: "OTP is required" }); - if (!email) return res.status(StatusCode.BadRequest).json({ message: "Email is required" }); - + const { accessToken, refreshToken } = await this.authDoctorUseCase.validateOtp(email, otp); res.cookie(Cookie.Doctor, refreshToken, { @@ -48,7 +38,6 @@ export default class AuthDoctorController { async resendOtp(req: Request, res: Response, next: NextFunction) { try { const { email } = req.body; - if (!email) return res.status(StatusCode.BadRequest).json({ message: "Email is Required" }); await this.authDoctorUseCase.resendOtp(email); res.status(StatusCode.Success).json({ message: "Otp Has Sended to email Address" }); } catch (error) { @@ -59,7 +48,6 @@ export default class AuthDoctorController { async forgotPassword(req: Request, res: Response, next: NextFunction) { try { const { email } = req.body; - if (!email) return res.status(StatusCode.BadRequest).json({ message: "Email is Required" }); await this.authDoctorUseCase.sendForgotPasswordMail(email); res.status(StatusCode.Success).json({ message: "Instruction has sended to email" }); @@ -71,14 +59,6 @@ export default class AuthDoctorController { try { const { email, password } = req.body; - if (!email) return res.status(StatusCode.BadRequest).json({ message: "Email is required" }); - if (!password?.trim()) { - return res.status(StatusCode.BadRequest).json({ message: "password is required" }); - } - if (!isValidatePassword(password)) { - return res.status(StatusCode.UnprocessableEntity).json({ message: "Password is too weak" }); - } - await this.authDoctorUseCase.updatePassword(email, password); res.status(StatusCode.Success).json({ message: "Password has updated" }); } catch (error) { @@ -89,29 +69,6 @@ export default class AuthDoctorController { async signup(req: Request, res: Response, next: NextFunction) { try { const doctor: IDoctor = req.body; - - if (!doctor.email?.trim()) { - return res.status(StatusCode.BadRequest).json({ message: "Email is required" }); - } - if (!isValidEmail(doctor.email)) { - return res.status(StatusCode.UnprocessableEntity).json({ message: "Invalid email format" }); - } - if (!doctor.password?.trim()) { - return res.status(StatusCode.BadRequest).json({ message: "Password is required" }); - } - if (!isValidatePassword(doctor.password)) { - return res.status(StatusCode.UnprocessableEntity).json({ message: "Password is too weak" }); - } - if (!doctor.name?.trim()) { - return res.status(StatusCode.BadRequest).json({ message: "Name is required" }); - } - if (!doctor.phone?.toString().trim()) { - return res.status(StatusCode.BadRequest).json({ message: "Phone number is required" }); - } - if (!doctor.qualifications || doctor.qualifications?.length < 1) { - return res.status(StatusCode.BadRequest).json({ message: "Qualifications is required" }); - } - const id = await this.authDoctorUseCase.register(doctor); res.status(StatusCode.Success).json({ message: "Signup successful", id }); } catch (error: any) { @@ -134,8 +91,6 @@ export default class AuthDoctorController { async uploadProfileImage(req: Request, res: Response, next: NextFunction) { try { const { key, id } = req.body; - if (!id.trim() || !key.trim()) - return res.status(StatusCode.BadRequest).json({ message: "Id and Key is Required" }); await this.authDoctorUseCase.updateProfileImage(key, id); res.status(StatusCode.Success).json({ message: "Profile image updated successfully" }); } catch (error) { diff --git a/server/src/presentation/routers/doctor/AuthenticationRoutes.ts b/server/src/presentation/routers/doctor/AuthenticationRoutes.ts index 4199291b..170ee3f4 100644 --- a/server/src/presentation/routers/doctor/AuthenticationRoutes.ts +++ b/server/src/presentation/routers/doctor/AuthenticationRoutes.ts @@ -7,9 +7,11 @@ import NodeMailerService from "../../../infrastructure/services/NodeMailerServic import DoctorRepository from "../../../infrastructure/repositories/DoctorRepository"; import OtpRepository from "../../../infrastructure/repositories/OtpRepository"; import S3StorageService from "../../../infrastructure/services/S3StorageService"; +import JoiService from "../../../infrastructure/services/JoiService"; const passwordService = new BcryptService(); const tokenService = new JWTService(); +const validatorService = new JoiService() const emailService = new NodeMailerService(); const cloudService = new S3StorageService(); const doctorRepository = new DoctorRepository(); @@ -21,7 +23,8 @@ const authUseCase = new AuthenticationUseCase( tokenService, emailService, otpRepository, - cloudService + cloudService, + validatorService ); const authDoctorController = new AuthDoctorController(authUseCase); diff --git a/server/src/use_case/doctor/AuthenticationUseCase.ts b/server/src/use_case/doctor/AuthenticationUseCase.ts index 787b9229..29b60de8 100644 --- a/server/src/use_case/doctor/AuthenticationUseCase.ts +++ b/server/src/use_case/doctor/AuthenticationUseCase.ts @@ -6,6 +6,7 @@ import IEmailService from "../../domain/interface/services/IEmailService"; import ITokenService from "../../domain/interface/services/ITokenService"; import { IPasswordServiceRepository } from "../../domain/interface/services/IPasswordServiceRepository"; import { UserRole } from "../../types"; +import IValidatorService from "../../domain/interface/services/IValidatorService"; export default class AuthenticationUseCase { constructor( @@ -14,10 +15,13 @@ export default class AuthenticationUseCase { private tokenService: ITokenService, private emailService: IEmailService, private otpRepository: IOtpRepository, - private cloudService: ICloudStorageService + private cloudService: ICloudStorageService, + private validatorService: IValidatorService ) { } async signin(email: string, password: string): Promise { + this.validatorService.validateEmailFormat(email) + this.validatorService.validatePassword(password) const doctor = await this.doctorRepository.findByEmailWithCredentials(email); if (!doctor) throw new Error("Not Found"); if (doctor.isBlocked) throw new Error("Doctor is Blocked"); @@ -41,6 +45,7 @@ export default class AuthenticationUseCase { } async validateOtp(email: string, otp: number): Promise<{ accessToken: string; refreshToken: string }> { + this.validatorService.validateEmailFormat(email) const isOtp = await this.otpRepository.findOne(otp, email); if (!isOtp) throw Error("Invalid Credentials"); @@ -60,6 +65,7 @@ export default class AuthenticationUseCase { } async resendOtp(email: string) { + this.validatorService.validateEmailFormat(email) const doctor = await this.doctorRepository.findByEmail(email); if (!doctor) throw new Error("Invalid Credentials"); @@ -79,6 +85,7 @@ export default class AuthenticationUseCase { } async sendForgotPasswordMail(email: string): Promise { + this.validatorService.validateEmailFormat(email) const doctor = await this.doctorRepository.findByEmail(email); if (!doctor) throw new Error("Invalid Credentials"); if (doctor.isBlocked) throw new Error("Doctor is Blocked"); @@ -92,6 +99,8 @@ export default class AuthenticationUseCase { } async updatePassword(email: string, password: string): Promise { + this.validatorService.validateEmailFormat(email) + this.validatorService.validatePassword(password) const doctor = await this.doctorRepository.findByEmail(email); if (!doctor) throw new Error("Invalid Credentials"); if (doctor.isBlocked) throw new Error("Doctor is Blocked"); @@ -101,12 +110,17 @@ export default class AuthenticationUseCase { } async register(doctor: IDoctor): Promise { + this.validatorService.validateRequiredFields({ email: doctor.email, name: doctor.name, password: doctor.password, phone: doctor.phone, qualification: doctor.qualifications }) + this.validatorService.validatePassword(doctor.password!); + this.validatorService.validateEmailFormat(doctor.email!); + this.validatorService.validatePhoneNumber(doctor.phone!); doctor.password = await this.passwordService.hash(doctor.password!); const id = await this.doctorRepository.create(doctor); return id; } async getPreSignedUrl(id: string): Promise<{ url: string; key: string }> { + this.validatorService.validateIdFormat(id); const doctor = await this.doctorRepository.findByID(id); if (!doctor) throw new Error("Not Found"); const key = `profile-images/${id}-${Date.now()}`; @@ -115,6 +129,7 @@ export default class AuthenticationUseCase { } async updateProfileImage(key: string, id: string): Promise { + this.validatorService.validateIdFormat(id) const doctor = await this.doctorRepository.findByID(id); if (!doctor) throw new Error("Not Found"); if (doctor.isBlocked) throw new Error("Doctor is Blocked");