Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 40 additions & 30 deletions src/controllers/userController.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
const Joi = require('joi');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const User = require('../models/userModel');
const sendEmail = require('../utils/sendEmail');
const Joi = require("joi");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const User = require("../models/userModel");
const sendEmail = require("../utils/sendEmail");

// Joi validation schema
const userSchema = Joi.object({
username: Joi.string().min(3).max(30).required(),
password: Joi.string().min(6).required(),
email: Joi.string().email().required(),
role: Joi.string().valid('user', 'admin', 'manager').default('user'),
phoneNumber: Joi.string().pattern(/^[0-9]{10,15}$/).required(),
role: Joi.string().valid("user", "admin", "manager").default("user"),
phoneNumber: Joi.string()
.pattern(/^[0-9]{10,15}$/)
.required(),
});

const loginSchema = Joi.object({
Expand All @@ -24,7 +26,7 @@ exports.getAllUsers = async (req, res) => {
const users = await User.find();
res.status(200).json(users);
} catch (err) {
res.status(500).json({ message: 'Error fetching users', error: err });
res.status(500).json({ message: "Error fetching users", error: err });
}
};

Expand All @@ -33,11 +35,11 @@ exports.getUserById = async (req, res) => {
try {
const user = await User.findById(req.params._id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
return res.status(404).json({ message: "User not found" });
}
res.status(200).json(user);
} catch (err) {
res.status(500).json({ message: 'Error fetching user', error: err });
res.status(500).json({ message: "Error fetching user", error: err });
}
};

Expand All @@ -46,7 +48,9 @@ exports.createUser = async (req, res) => {
try {
const { error } = userSchema.validate(req.body);
if (error) {
return res.status(400).json({ message: 'Validation error', error: error.details[0].message });
return res
.status(400)
.json({ message: "Validation error", error: error.details[0].message });
}

// Hash the password before saving
Expand All @@ -64,27 +68,29 @@ exports.createUser = async (req, res) => {
const token = jwt.sign(
{ id: user._id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '1h' } // Token expires in 1 hour
{ expiresIn: "1h" }, // Token expires in 1 hour
);

// Generate verification token
const verificationToken = jwt.sign(
{ id: user._id },
process.env.JWT_SECRET,
{ expiresIn: '7d' } // Token expires in 7 days
{ expiresIn: "7d" }, // Token expires in 7 days
);

// Send verification email
const verificationLink = `http://localhost:3000/api/users/verify/${verificationToken}`;
const verificationLink = process.env.LIVE_API_URL
? `${process.env.LIVE_API_URL}/api/users/verify/${verificationToken}`
: `http://localhost:3000/api/users/verify/${verificationToken}`;
await sendEmail(
user.email,
'Email Verification',
`Please verify your email by clicking on the following link: ${verificationLink}`
"Email Verification",
`Please verify your email by clicking on the following link: ${verificationLink}`,
);

res.status(201).json({ user, token }); // Send user and token in response
} catch (err) {
res.status(400).json({ message: 'Error creating user', error: err });
res.status(400).json({ message: "Error creating user", error: err });
}
};

Expand All @@ -93,19 +99,21 @@ exports.updateUser = async (req, res) => {
try {
const { error } = userSchema.validate(req.body);
if (error) {
return res.status(400).json({ message: 'Validation error', error: error.details[0].message });
return res
.status(400)
.json({ message: "Validation error", error: error.details[0].message });
}

const user = await User.findByIdAndUpdate(req.params._id, req.body, {
new: true,
runValidators: true,
});
if (!user) {
return res.status(404).json({ message: 'User not found' });
return res.status(404).json({ message: "User not found" });
}
res.status(200).json(user);
} catch (err) {
res.status(400).json({ message: 'Error updating user', error: err });
res.status(400).json({ message: "Error updating user", error: err });
}
};

Expand All @@ -114,50 +122,52 @@ exports.deleteUser = async (req, res) => {
try {
const user = await User.findByIdAndDelete(req.params._id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
return res.status(404).json({ message: "User not found" });
}
res.status(200).json({ message: 'User deleted successfully' });
res.status(200).json({ message: "User deleted successfully" });
} catch (err) {
res.status(500).json({ message: 'Error deleting user', error: err });
res.status(500).json({ message: "Error deleting user", error: err });
}
};

exports.loginUser = async (req, res) => {
try {
const { error } = loginSchema.validate(req.body);
if (error) {
return res.status(400).json({ message: 'Validation error', error: error.details[0].message });
return res
.status(400)
.json({ message: "Validation error", error: error.details[0].message });
}

const { email, password } = req.body;

// Find user by email
const user = await User.findOne({ email });
if (!user) {
return res.status(401).json({ message: 'Invalid email or password' });
return res.status(401).json({ message: "Invalid email or password" });
}

// Check if the email is verified
if (!user.emailVerified) {
return res.status(401).json({ message: 'Email not verified' });
return res.status(401).json({ message: "Email not verified" });
}

// Compare passwords
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).json({ message: 'Invalid email or password' });
return res.status(401).json({ message: "Invalid email or password" });
}

// Generate JWT token
const token = jwt.sign(
{ id: user._id, role: user.role },
process.env.JWT_SECRET,
{ expiresIn: '1h' } // Token expires in 1 hour
{ expiresIn: "1h" }, // Token expires in 1 hour
);

// Respond with token and user info
res.status(200).json({
message: 'Login successful',
message: "Login successful",
token,
user: {
id: user._id,
Expand All @@ -167,6 +177,6 @@ exports.loginUser = async (req, res) => {
},
});
} catch (err) {
res.status(500).json({ message: 'Error logging in', error: err });
res.status(500).json({ message: "Error logging in", error: err });
}
};