import { Request, Response } from 'express'; import User from '../models/users'; import { comparePassword, hashPassword } from '../utils/passwordUtils'; import { generateToken } from '../utils/jwtUtils'; import { logger } from '../utils/logger'; import { sendMail } from '../utils/mailer'; import { generateResetToken } from '../utils/tokenUtils'; import { Op } from 'sequelize'; import { AuthenticatedRequest } from 'shared/interfaces/user.interface'; export const login = async (req: Request, res: Response) => { try { const { email, password } = req.body; const user = await User.findOne({ where: { email: email, }, }) if (!user) { return res.status(401).json({ error: 'Invalid Credentials' }); } const passwordMatch = await comparePassword(password, user.password); if (!passwordMatch) { return res.status(401).json({ error: 'Invalid Credentials' }); } if (user.status === 'inactive') { return res.status(403).json({ error: 'Forbidden' }); } const payload = { id: user.id, name: user.name, email: user.email, role_id: user.role_id } const token = generateToken(payload); return res.status(200).json({ token: token }); } catch (error) { logger.error("Error logging in: "); logger.error(error); return res.status(500).json({ error: 'Internal server error' }); } } export const forgotPassword = async (req: Request, res: Response) => { try { const { email } = req.body; const user = await User.findOne({ where: { email } }); if (!user) { return res.status(404).json({ error: 'User not found' }); } const resetToken = generateResetToken(); const resetTokenExpiry = new Date(Date.now() + 3600000); await user.update({ reset_token: resetToken, reset_token_expiry: resetTokenExpiry }); const resetLink = `${process.env.APP_URL}reset-password?token=${resetToken}`; sendMail({ subject: 'Your password reset link', to: email, content: `

Dear ${user.name},

Click the link below to reset your password:

Reset Your Password

Link will expire within 1 hour.

Best regards,
Team Fusion Bills

` }) return res.status(200).json({ message: 'Password reset email sent successfully' }); } catch (error) { logger.error("Error in forgot password: "); logger.error(error); return res.status(500).json({ error: 'Internal server error' }); } } export const resetPassword = async (req: Request, res: Response) => { try { const { token, newPassword } = req.body; const user = await User.findOne({ where: { reset_token: token, reset_token_expiry: { [Op.gt]: new Date() } } }); if (!user) { return res.status(400).json({ error: 'Invalid or expired token' }); } const hashedPassword = await hashPassword(newPassword); await user.update({ password: hashedPassword, reset_token: null, reset_token_expiry: null }); return res.status(200).json({ message: 'Password reset successfully' }); } catch (error) { logger.error("Error in reset password: "); logger.error(error); return res.status(500).json({ error: 'Internal server error' }); } } export const changePassword = async (req: AuthenticatedRequest, res: Response) => { try { const { currentPassword, newPassword, confirmPassword } = req.body; const userId = req.user?.id; if (!userId) { return res.status(401).json({ error: 'Unauthorized' }); } const user = await User.findByPk(userId); if (!user) { return res.status(404).json({ error: 'User not found' }); } const isPasswordCorrect = await comparePassword(currentPassword, user.password); if (!isPasswordCorrect) { return res.status(400).json({ error: 'Invalid current password' }); } if (newPassword !== confirmPassword) { return res.status(400).json({ error: 'New passwords do not match' }); } if (newPassword.length < 8) { return res.status(400).json({ error: 'Password must be at least 8 characters long.' }); } const hashedPassword = await hashPassword(newPassword); user.password = hashedPassword; await user.save(); return res.status(200).json({ message: 'Password changed successfully' }); } catch (error) { logger.error("Error changing password: "); logger.error(error); return res.status(500).json({ error: 'Internal server error' }); } }