Loading hono-postgres-setup/src/user/user.controller.ts +68 −12 Original line number Diff line number Diff line import { Context } from "hono"; import db from "../../db/db.connect"; import { users } from "../models/user.model"; import { eq } from "drizzle-orm"; import { eq, gt, and } from "drizzle-orm"; import { hashPassword, verifyPassword } from "./password.utill"; import { verificationTokens } from "../models/verification.token.model"; import crypto from 'crypto'; import crypto from "crypto"; export const registerUser = async (c: Context) => { const body = await c.req.json(); Loading Loading @@ -61,8 +61,8 @@ export const loginUser = async (c: Context) => { id: user.id, email: user.email, firstName: user.firstName, lastName: user.lastName } lastName: user.lastName, }, }); }; Loading @@ -73,28 +73,84 @@ export const forgotPassword = async (c: Context) => { const [user] = await db.select().from(users).where(eq(users.email, email)); if (!user) { return c.json({ error: 'User not found' }, 404); return c.json({ error: "User not found" }, 404); } // Create the expiry date (1 day from now) const expiryDate = new Date(); expiryDate.setDate(expiryDate.getDate() + 1); const token = crypto.randomBytes(32).toString('hex'); const token = crypto.randomBytes(32).toString("hex"); await db.insert(verificationTokens).values({ userAccountId: user.id, token: token, type: 'PWD_RESET', type: "PWD_RESET", notificationTime: null, expiryTime: expiryDate, createdAt: new Date(), updatedAt: new Date(), }); return c.json({ status: 'SUCCESS' }, 200); return c.json({ status: "SUCCESS" }, 200); } catch (error) { console.error('Error in forgotPassword:', error); return c.json({ error: 'Internal Server Error' }, 500); console.error("Error in forgotPassword:", error); return c.json({ error: "Internal Server Error" }, 500); } }; export const passwordReset = async (c: Context) => { const body = await c.req.json(); const tokenValue = body.token; const newPassword = body.password; // Find the token in the verificationTokens table const tokenResult = await db .select() .from(verificationTokens) .where( and( eq(verificationTokens.token, tokenValue), eq(verificationTokens.type, "PWD_RESET"), gt(verificationTokens.expiryTime, new Date()) ) ); if (tokenResult.length === 0) { return c.json( { error: "Invalid password recovery link or the link has expired." }, 400 ); } const token = tokenResult[0]; // Find the user account associated with the token const userResult = await db .select() .from(users) .where(eq(users.id, token.userAccountId)); if (userResult.length === 0) { return c.json( { error: "Invalid password recovery link or the link has expired." }, 400 ); } const user = userResult[0]; // Reset the password const hashedPassword = await hashPassword(newPassword); await db .update(users) .set({ password: hashedPassword }) .where(eq(users.id, user.id)); // Delete the used token await db .delete(verificationTokens) .where(eq(verificationTokens.id, token.id)); return c.json({ status: "SUCCESS" }); }; hono-postgres-setup/src/user/user.route.ts +19 −1 Original line number Diff line number Diff line import { Hono } from "hono"; import { forgotPassword, loginUser, registerUser } from "./user.controller"; import { forgotPassword, loginUser, passwordReset, registerUser, } from "./user.controller"; import { forgotPasswordSchema, loginSchema, passwordResetSchema, registrationSchema, } from "./user.validation.schema"; Loading Loading @@ -42,4 +48,16 @@ export const userRoutes = (app: Hono) => { return forgotPassword(c); }); app.post("/user/password-reset", async (c) => { const body = await c.req.json(); try { passwordResetSchema.parse(body); } catch (error: any) { return c.json({ error: error.errors }, 400); } return passwordReset(c); }); }; hono-postgres-setup/src/user/user.validation.schema.ts +9 −1 Original line number Diff line number Diff line Loading @@ -20,4 +20,12 @@ const forgotPasswordSchema = z.object({ email: z.string().nonempty("Email is required").email("Invalid email format"), }); export { registrationSchema, loginSchema, forgotPasswordSchema }; const passwordResetSchema = z.object({ token: z.string().nonempty("Token is required"), password: z .string() .nonempty("Password is required") .min(4, "Password must be at least 4 characters long"), }); export { registrationSchema, loginSchema, forgotPasswordSchema, passwordResetSchema }; Loading
hono-postgres-setup/src/user/user.controller.ts +68 −12 Original line number Diff line number Diff line import { Context } from "hono"; import db from "../../db/db.connect"; import { users } from "../models/user.model"; import { eq } from "drizzle-orm"; import { eq, gt, and } from "drizzle-orm"; import { hashPassword, verifyPassword } from "./password.utill"; import { verificationTokens } from "../models/verification.token.model"; import crypto from 'crypto'; import crypto from "crypto"; export const registerUser = async (c: Context) => { const body = await c.req.json(); Loading Loading @@ -61,8 +61,8 @@ export const loginUser = async (c: Context) => { id: user.id, email: user.email, firstName: user.firstName, lastName: user.lastName } lastName: user.lastName, }, }); }; Loading @@ -73,28 +73,84 @@ export const forgotPassword = async (c: Context) => { const [user] = await db.select().from(users).where(eq(users.email, email)); if (!user) { return c.json({ error: 'User not found' }, 404); return c.json({ error: "User not found" }, 404); } // Create the expiry date (1 day from now) const expiryDate = new Date(); expiryDate.setDate(expiryDate.getDate() + 1); const token = crypto.randomBytes(32).toString('hex'); const token = crypto.randomBytes(32).toString("hex"); await db.insert(verificationTokens).values({ userAccountId: user.id, token: token, type: 'PWD_RESET', type: "PWD_RESET", notificationTime: null, expiryTime: expiryDate, createdAt: new Date(), updatedAt: new Date(), }); return c.json({ status: 'SUCCESS' }, 200); return c.json({ status: "SUCCESS" }, 200); } catch (error) { console.error('Error in forgotPassword:', error); return c.json({ error: 'Internal Server Error' }, 500); console.error("Error in forgotPassword:", error); return c.json({ error: "Internal Server Error" }, 500); } }; export const passwordReset = async (c: Context) => { const body = await c.req.json(); const tokenValue = body.token; const newPassword = body.password; // Find the token in the verificationTokens table const tokenResult = await db .select() .from(verificationTokens) .where( and( eq(verificationTokens.token, tokenValue), eq(verificationTokens.type, "PWD_RESET"), gt(verificationTokens.expiryTime, new Date()) ) ); if (tokenResult.length === 0) { return c.json( { error: "Invalid password recovery link or the link has expired." }, 400 ); } const token = tokenResult[0]; // Find the user account associated with the token const userResult = await db .select() .from(users) .where(eq(users.id, token.userAccountId)); if (userResult.length === 0) { return c.json( { error: "Invalid password recovery link or the link has expired." }, 400 ); } const user = userResult[0]; // Reset the password const hashedPassword = await hashPassword(newPassword); await db .update(users) .set({ password: hashedPassword }) .where(eq(users.id, user.id)); // Delete the used token await db .delete(verificationTokens) .where(eq(verificationTokens.id, token.id)); return c.json({ status: "SUCCESS" }); };
hono-postgres-setup/src/user/user.route.ts +19 −1 Original line number Diff line number Diff line import { Hono } from "hono"; import { forgotPassword, loginUser, registerUser } from "./user.controller"; import { forgotPassword, loginUser, passwordReset, registerUser, } from "./user.controller"; import { forgotPasswordSchema, loginSchema, passwordResetSchema, registrationSchema, } from "./user.validation.schema"; Loading Loading @@ -42,4 +48,16 @@ export const userRoutes = (app: Hono) => { return forgotPassword(c); }); app.post("/user/password-reset", async (c) => { const body = await c.req.json(); try { passwordResetSchema.parse(body); } catch (error: any) { return c.json({ error: error.errors }, 400); } return passwordReset(c); }); };
hono-postgres-setup/src/user/user.validation.schema.ts +9 −1 Original line number Diff line number Diff line Loading @@ -20,4 +20,12 @@ const forgotPasswordSchema = z.object({ email: z.string().nonempty("Email is required").email("Invalid email format"), }); export { registrationSchema, loginSchema, forgotPasswordSchema }; const passwordResetSchema = z.object({ token: z.string().nonempty("Token is required"), password: z .string() .nonempty("Password is required") .min(4, "Password must be at least 4 characters long"), }); export { registrationSchema, loginSchema, forgotPasswordSchema, passwordResetSchema };