import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import Joi from 'joi';
import { PrismaClient } from '@prisma/client';
import { Request, Response } from 'express';
const prisma = new PrismaClient();
// Custom validation schema with detailed error messages
const registerSchema = Joi.object({
displayName: Joi.string().min(3).max(30).required().messages({
'string.base': 'Display name must be a string',
'string.empty': 'Display name is required',
'string.min': 'Display name should have a minimum length of {#limit}',
'string.max': 'Display name should have a maximum length of {#limit}',
}),
email: Joi.string().email().required().messages({
'string.email': 'Please enter a valid email address',
'string.empty': 'Email is required',
}),
password: Joi.string().min(6).required().messages({
'string.min': 'Password should have a minimum length of {#limit}',
'string.empty': 'Password is required',
}),
});
/**
* Register a new user.
* @param {Request} req - The request object.
* @param {Response} res - The response object.
* @returns {Promise<void>}
*/
export const register = async (req: Request, res: Response): Promise<void> => {
try {
// Validate the request body
const { error } = registerSchema.validate(req.body);
if (error) {
res.status(400).json({ error: error.details[0].message });
return;
}
const { displayName, email, password } = req.body;
// Check if user already exists
const existingUser = await prisma.user.findUnique({ where: { email } });
if (existingUser) {
res.status(400).json({ error: 'User with this email already exists' });
return;
}
const hashedPassword = await bcrypt.hash(password, 10);
const user = await prisma.user.create({
data: {
displayName,
email,
password: hashedPassword,
},
});
res.status(201).json(user);
} catch (error) {
res.status(500).json({ error: (error as any).message });
}
};
const loginSchema = Joi.object({
email: Joi.string().email().required().messages({
'string.email': 'Please enter a valid email address',
'string.empty': 'Email is required',
}),
password: Joi.string().min(6).required().messages({
'string.min': 'Password should have a minimum length of {#limit}',
'string.empty': 'Password is required',
}),
});
/**
* Login a user.
* @param {Request} req - The request object.
* @param {Response} res - The response object.
* @returns {Promise<void>}
*/
export const login = async (req: Request, res: Response): Promise<void> => {
// Validate the request body
const { error } = loginSchema.validate(req.body);
if (error) {
res.status(400).json({ error: error.details[0].message });
return;
}
const { email, password } = req.body;
const user = await prisma.user.findUnique({
where: { email },
});
if (!user || !bcrypt.compareSync(password, user.password)) {
res.status(401).json({ message: 'Invalid credentials' });
return;
}
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET as string, { expiresIn: '1h' });
res.status(200).json({ token });
};