diff --git a/server/.gitignore b/server/.gitignore
index bf898501..65d04bd1 100644
--- a/server/.gitignore
+++ b/server/.gitignore
@@ -38,3 +38,4 @@ pnpm-debug.log*
*.sw?
# Mac
+.vercel
diff --git a/server/public/resetPasswordTemplate.html b/server/public/resetPasswordTemplate.html
new file mode 100644
index 00000000..3478d6c1
--- /dev/null
+++ b/server/public/resetPasswordTemplate.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+ Reset Your Password
+
+
+
+
+
Hello, {{name}}!
+
We received a request to reset your password. You can reset your password by clicking the button below:
+
Reset Password
+
This link is valid for only 1 hour. Please make sure to use it before it expires.
+
If you did not request a password reset, please ignore this email or contact our support team immediately.
+
+
+
+
diff --git a/server/src/infrastructure/database/repositories/OtpRepository.ts b/server/src/infrastructure/repositories/OtpRepository.ts
similarity index 72%
rename from server/src/infrastructure/database/repositories/OtpRepository.ts
rename to server/src/infrastructure/repositories/OtpRepository.ts
index 4d62bff6..d417b180 100644
--- a/server/src/infrastructure/database/repositories/OtpRepository.ts
+++ b/server/src/infrastructure/repositories/OtpRepository.ts
@@ -1,6 +1,6 @@
-import IOtp from "../../../domain/entities/IOtp";
-import IOtpRepository from "../../../interface/repositories/IOtpRepository";
-import OtpModel from "../models/OtpModel";
+import IOtp from "../../domain/entities/IOtp";
+import IOtpRepository from "../../interface/repositories/IOtpRepository";
+import OtpModel from "../database/models/OtpModel";
export default class OtpRepository implements IOtpRepository {
model = OtpModel;
diff --git a/server/src/infrastructure/database/repositories/PatientRepository.ts b/server/src/infrastructure/repositories/PatientRepository.ts
similarity index 83%
rename from server/src/infrastructure/database/repositories/PatientRepository.ts
rename to server/src/infrastructure/repositories/PatientRepository.ts
index 3e279859..e1cee381 100644
--- a/server/src/infrastructure/database/repositories/PatientRepository.ts
+++ b/server/src/infrastructure/repositories/PatientRepository.ts
@@ -1,7 +1,7 @@
-import { IPatient } from "../../../domain/entities/Patient";
-import IPatientRepository from "../../../interface/repositories/IPatientRepository";
-import { isValidObjectId } from "../isValidObjId";
-import PatientModel from "../models/PatientModel";
+import { IPatient } from "../../domain/entities/Patient";
+import IPatientRepository from "../../interface/repositories/IPatientRepository";
+import { isValidObjectId } from "../database/isValidObjId";
+import PatientModel from "../database/models/PatientModel";
export default class PatientRepository implements IPatientRepository {
model = PatientModel;
diff --git a/server/src/infrastructure/services/EmailService.ts b/server/src/infrastructure/services/EmailService.ts
index 78333646..ecd77ee7 100644
--- a/server/src/infrastructure/services/EmailService.ts
+++ b/server/src/infrastructure/services/EmailService.ts
@@ -1,35 +1,60 @@
import IEmailService from "../../interface/services/IEmailService";
import nodemailer from "nodemailer";
-import {promisify} from 'util'
-import fs from 'fs'
-import path from 'path'
-
+import { promisify } from "util";
+import fs from "fs";
+import path from "path";
const readFileAsync = promisify(fs.readFile);
-export default class EmailService implements IEmailService{
-
- async sendOtp(email: string, name: string, otp: number): Promise {
- let htmlTemplate = await readFileAsync(path.join(__dirname, '../../../public/otpEmailTemplate.html'), 'utf-8');
-
- htmlTemplate = htmlTemplate.replace('{{name}}', name);
- htmlTemplate = htmlTemplate.replace('{{otp}}', otp.toString());
-
- const transporter = nodemailer.createTransport({
- service: 'gmail',
- auth: {
- user: process.env.SENDER_EMAIL,
- pass: process.env.NODEMAILER_PASSKEY,
- },
- });
-
- await transporter.sendMail({
- from: process.env.SENDER_MAIL,
- to: email,
- subject: 'Your OTP for Verification',
- html: htmlTemplate,
- });
-
- }
-
+export default class EmailService implements IEmailService {
+ async sendOtp(email: string, name: string, otp: number): Promise {
+ let htmlTemplate = await readFileAsync(path.join(__dirname, "../../../public/otpEmailTemplate.html"), "utf-8");
+
+ htmlTemplate = htmlTemplate.replace("{{name}}", name);
+ htmlTemplate = htmlTemplate.replace("{{otp}}", otp.toString());
+
+ const transporter = nodemailer.createTransport({
+ service: "gmail",
+ auth: {
+ user: process.env.SENDER_EMAIL,
+ pass: process.env.NODEMAILER_PASSKEY,
+ },
+ });
+
+ const id = await transporter.sendMail({
+ from: process.env.SENDER_MAIL,
+ to: email,
+ subject: "No Reply Mail: Otp Verification",
+ html: htmlTemplate,
+ });
+
+ console.log(id.messageId);
+
+ }
+
+ async sendResetMail(email: string, name: string, resetLink: string): Promise {
+ let htmlTemplate = await readFileAsync(
+ path.join(__dirname, "../../../public/resetPasswordTemplate.html"),
+ "utf-8"
+ );
+
+ htmlTemplate = htmlTemplate.replace("{{name}}", name);
+ htmlTemplate = htmlTemplate.replace("{{resetLink}}", resetLink);
+
+ const transporter = nodemailer.createTransport({
+ service: "gmail",
+ auth: {
+ user: process.env.SENDER_EMAIL,
+ pass: process.env.NODEMAILER_PASSKEY,
+ },
+ });
+
+ const mail = await transporter.sendMail({
+ from: process.env.SENDER_MAIL,
+ to: email,
+ subject: "No Reply Mail: Password Reset",
+ html: htmlTemplate,
+ });
+
+ };
}
diff --git a/server/src/interface/services/IEmailService.ts b/server/src/interface/services/IEmailService.ts
index 44e4c904..b942ef54 100644
--- a/server/src/interface/services/IEmailService.ts
+++ b/server/src/interface/services/IEmailService.ts
@@ -1,3 +1,4 @@
export default interface IEmailService {
sendOtp(email: string, name: string, otp: number): Promise;
+ sendResetMail(email:string,name:string,resetLink:string):Promise;
}
diff --git a/server/src/presentation/controllers/PatientController.ts b/server/src/presentation/controllers/PatientController.ts
index 239eeb96..d53ecc79 100644
--- a/server/src/presentation/controllers/PatientController.ts
+++ b/server/src/presentation/controllers/PatientController.ts
@@ -62,7 +62,7 @@ export default class PatientController {
const { email } = req.body;
if (!email) return res.status(400).json({ message: "Email is required" });
await this.authPatientUseCase.resendOtp(email);
- res.status(200).json({message:"Otp Sended to the mail Address"});
+ res.status(200).json({ message: "Otp Sended to the mail Address" });
} catch (error: any) {
if (error.message === "Patient Not Found") {
return res.status(422).json({ message: "Invalid Credentials" });
@@ -93,6 +93,16 @@ export default class PatientController {
}
}
+ async resetPassword(req: Request, res: Response, next: NextFunction) {
+ try {
+ const { email } = req.body;
+ if (!email) return res.status(400).json({ message: "Email is Required" });
+ await this.authPatientUseCase.sendForgetPasswordMail(email);
+ } catch (error: any) {
+ next(error);
+ }
+ }
+
async refreshAccessToken(req: Request, res: Response, next: NextFunction) {
try {
const cookies = req.cookies;
diff --git a/server/src/presentation/middlewares/errorHandler.ts b/server/src/presentation/middlewares/errorHandler.ts
index 11478fee..bdfd398f 100644
--- a/server/src/presentation/middlewares/errorHandler.ts
+++ b/server/src/presentation/middlewares/errorHandler.ts
@@ -16,7 +16,7 @@ export const errorHandler = (err: any, req: Request, res: Response, next: NextFu
return res.status(401).json({ message: err.message });
} else if (err.message === "Patient is blocked") {
return res.status(403).json({ message: err.message });
- }else if (err.message==="Patient not found"){
+ }else if (err.message==="Patient not Found"){
return res.status(404).json({message:err.message})
}else if (err.message===' getaddrinfo ENOTFOUND smtp.gmail.com'){
return res.status(500).json({message:"We are Having Issue with Email Service"})
diff --git a/server/src/presentation/routers/patient/AuthPatientRoutes.ts b/server/src/presentation/routers/patient/AuthPatientRoutes.ts
index 581520a8..724ba465 100644
--- a/server/src/presentation/routers/patient/AuthPatientRoutes.ts
+++ b/server/src/presentation/routers/patient/AuthPatientRoutes.ts
@@ -1,28 +1,42 @@
import express from "express";
-import PatientRepository from "../../../infrastructure/database/repositories/PatientRepository";
+import PatientRepository from "../../../infrastructure/repositories/PatientRepository";
import PasswordService from "../../../infrastructure/services/PasswordService";
import RegisterPatientUseCase from "../../../use_case/patient/RegisterPatientUseCase";
import PatientController from "../../controllers/PatientController";
import AuthPatientUseCase from "../../../use_case/patient/AuthPatientUseCase";
import EmailService from "../../../infrastructure/services/EmailService";
-import OtpRepository from "../../../infrastructure/database/repositories/OtpRepository";
+import OtpRepository from "../../../infrastructure/repositories/OtpRepository";
import TokenService from "../../../infrastructure/services/TokenService";
-import PatientAuthMiddleware from "../../middlewares/PatientAuthMiddleware";
+import PatientAuthMiddleware from "../../middlewares/PatientAuthMiddleware";
-const route = express();
+const route = express.Router();
+// Services and Repositories
const emailService = new EmailService();
const tokenService = new TokenService();
const otpRepository = new OtpRepository();
const passwordService = new PasswordService();
const patientRepository = new PatientRepository();
+
+// Use Cases
const registerPatientUseCase = new RegisterPatientUseCase(patientRepository, passwordService);
-const authPatientUseCase = new AuthPatientUseCase(patientRepository, passwordService, emailService, otpRepository, tokenService);
+const authPatientUseCase = new AuthPatientUseCase(
+ patientRepository,
+ passwordService,
+ emailService,
+ otpRepository,
+ tokenService
+);
+
+// Controllers
const patientController = new PatientController(registerPatientUseCase, authPatientUseCase);
-const patientAuthMiddleWare = new PatientAuthMiddleware (tokenService);
-route.post("/", (req, res, next) => {
- patientController.register(req, res, next);
+// Middleware
+const patientAuthMiddleware = new PatientAuthMiddleware(tokenService);
+
+
+route.post("/register", (req, res, next) => {
+ patientController.register(req, res, next);
});
route.post("/login", (req, res, next) => {
patientController.login(req, res, next);
@@ -33,11 +47,14 @@ route.post("/resend-otp", (req, res, next) => {
route.post("/otp-verification", (req, res, next) => {
patientController.validateOtp(req, res, next);
});
-route.get("/refresh",(req,res,next)=>{
- patientController.refreshAccessToken(req,res,next);
+route.get("/refresh", (req, res, next) => {
+ patientController.refreshAccessToken(req, res, next);
+});
+route.post("/reset-password", (req, res, next) => {
+ patientController.resetPassword(req, res, next);
});
-route.post('/logout',patientAuthMiddleWare.exec,(req,res,next)=>{
- patientController.logout(req,res,next)
+route.post("/logout", patientAuthMiddleware.exec, (req, res, next) => {
+ patientController.logout(req, res, next);
});
export default route;
diff --git a/server/src/use_case/patient/AuthPatientUseCase.ts b/server/src/use_case/patient/AuthPatientUseCase.ts
index 6e3396a3..4d31c35d 100644
--- a/server/src/use_case/patient/AuthPatientUseCase.ts
+++ b/server/src/use_case/patient/AuthPatientUseCase.ts
@@ -24,9 +24,9 @@ export default class LoginPatientUseCase {
if (foundedPatient.isBlocked) throw new Error("Unauthorized");
- let otp = parseInt(generateOTP(6),10);
+ let otp = parseInt(generateOTP(6), 10);
while (otp.toString().length !== 6) {
- otp = parseInt(generateOTP(6),10);
+ otp = parseInt(generateOTP(6), 10);
}
await this.otpRepository.create(otp, foundedPatient.email!);
@@ -39,9 +39,9 @@ export default class LoginPatientUseCase {
const patient = await this.patientRepository.findByEmail(email);
if (!patient) throw new Error("Patient Not Found");
- let otp = parseInt(generateOTP(6),10);
+ let otp = parseInt(generateOTP(6), 10);
while (otp.toString().length !== 6) {
- otp = parseInt(generateOTP(6),10);
+ otp = parseInt(generateOTP(6), 10);
}
await this.otpRepository.create(otp, email);
await this.emailService.sendOtp(email, patient.name!, otp);
@@ -78,4 +78,11 @@ export default class LoginPatientUseCase {
return { accessToken };
}
+
+ async sendForgetPasswordMail(email: string): Promise {
+ const patient = await this.patientRepository.findByEmail(email);
+ if (!patient) throw new Error("Patient Not Found");
+ if (patient.isBlocked) throw new Error("Patient is Blocked");
+ await this.emailService.sendResetMail(email, patient.name!, `${process.env.CLIENT_URL}/signin/reset-password`!);
+ }
}