Skip to content

Commit

Permalink
doctor validation with joi added
Browse files Browse the repository at this point in the history
  • Loading branch information
sinanptm committed Sep 15, 2024
1 parent d551369 commit effa75c
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 49 deletions.
2 changes: 1 addition & 1 deletion server/src/infrastructure/services/JoiService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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, {
Expand All @@ -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) {
Expand All @@ -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" });
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -21,7 +23,8 @@ const authUseCase = new AuthenticationUseCase(
tokenService,
emailService,
otpRepository,
cloudService
cloudService,
validatorService
);
const authDoctorController = new AuthDoctorController(authUseCase);

Expand Down
17 changes: 16 additions & 1 deletion server/src/use_case/doctor/AuthenticationUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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<void> {
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");
Expand All @@ -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");

Expand All @@ -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");

Expand All @@ -79,6 +85,7 @@ export default class AuthenticationUseCase {
}

async sendForgotPasswordMail(email: string): Promise<void> {
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");
Expand All @@ -92,6 +99,8 @@ export default class AuthenticationUseCase {
}

async updatePassword(email: string, password: string): Promise<void> {
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");
Expand All @@ -101,12 +110,17 @@ export default class AuthenticationUseCase {
}

async register(doctor: IDoctor): Promise<string> {
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()}`;
Expand All @@ -115,6 +129,7 @@ export default class AuthenticationUseCase {
}

async updateProfileImage(key: string, id: string): Promise<void> {
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");
Expand Down

0 comments on commit effa75c

Please sign in to comment.