Mongodb-Practice-1
I am Learner.
PORT=3000
SECRET=SECRET
MONGO_URI="mongodb://127.0.0.1:27017/mongodb_practice"
//REFRESH_SECRET=refresh
//ACCESS_SECRET=access
const express = require('express');
require('dotenv').config();
const path = require("path");
const connectDb = require('./utils/db');
const adminSeeder = require("./seeder/adminSeeder");
const authRoutes = require("./router/auth.routes");
const userRoutes = require("./router/user.routes");
const taskRoutes = require("./router/task.routes");
const app = express();
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));
app.use(express.json());
app.use("/uploads", express.static("uploads"));
app.use("/auth", authRoutes);
app.use("/user", userRoutes);
app.use("/task", taskRoutes);
connectDb().then(async () => {
await adminSeeder();
app.listen(process.env.PORT, () => {
console.log(` Server is running on http://localhost:${process.env.PORT}`);
});
});
const mongoose = require('mongoose');
const connectDb = async () => {
try {
await mongoose.connect(process.env.MONGO_URI);
console.log("MongoDB connected successfully");
} catch (error) {
console.error(" Error connecting to MongoDB:", error);
process.exit(1); // Exit process if DB fails
}
};
module.exports = connectDb;
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
userName: {
type: String,
default: ""
},
email: {
type: String,
default: "",
unique: true
},
password: {
type: String,
default: ""
},
role: {
type: String,
enum: ['User', 'Admin'],
default: 'User'
},
birthDate: {
type: Date
},
age: {
type: Number
},
profileImage: {
type: String,
default: ""
},
sessions: [{ token: String, createdAt: Date }]
}, {
timestamps: true
});
const User = mongoose.model('User', userSchema);
module.exports = User;
const mongoose = require('mongoose');
const assignSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
status: {
type: String,
enum: ['Pending', 'Ongoing', 'Completed']
}
});
const commentsSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
media: {
type: String,
default: " "
},
comment: {
type: String,
default: ""
}
})
const taskSchema = new mongoose.Schema({
taskName: {
type: String,
default: ""
},
description: {
type: String,
default: ""
},
isDeleted: {
type: Boolean,
default: false
},
createdBy: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
comments: [commentsSchema],
assignTask: [assignSchema]
}, {
timestamps: true
});
const Task = mongoose.model('Task', taskSchema);
module.exports = Task;
const mongoose = require("mongoose");
const interestSchema = new mongoose.Schema({
name: {
type: [String],
required: true
},
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true
}
}, { timestamps: true });
module.exports = mongoose.model("Interest", interestSchema);
const User = require("../model/user.model.js");
const bcrypt = require("bcrypt");
const adminSeeder = async (req, res) => {
try {
const email = 'a@a.com';
const password = '123456';
const isExistingUser = await User.findOne({ email });
if (isExistingUser) {
console.log("Admin already exists.");
if (res) return res.status(200).json({ message: "Admin already exists" });
return;
}
const hashedPassword = await bcrypt.hash(password, 10);
const adminUser = new User({
userName: 'Admin',
email,
password: hashedPassword,
role: 'Admin',
sessions: []
});
await adminUser.save();
console.log("Admin created successfully:", adminUser);
if (res) {
return res.status(201).json({
message: "Admin created successfully",
admin: {
userName: adminUser.userName,
email: adminUser.email,
role: adminUser.role
}
});
}
} catch (error) {
console.error(" Error creating admin:", error);
if (res) return res.status(500).json({ message: "Error creating admin", error: error.message });
}
};
module.exports = adminSeeder;
const multer = require("multer");
const path = require("path");
const storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, 'uploads/'),
filename: (req, file, cb) => cb(null, Date.now() + path.extname(file.originalname)),
});
const fileFilter = (req, file, cb) => {
const allowedTypes = /jpeg|jpg|png|gif|webp/;
const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase());
const mimetype = allowedTypes.test(file.mimetype);
if (mimetype && extname) {
cb(null, true);
} else {
cb(new Error('Only image files are allowed!'));
}
};
const upload = multer({
storage,
fileFilter,
limits: { fileSize: 5 * 1024 * 1024 },
});
module.exports = upload;
const express = require('express');
const router = express.Router();
const validate = require("../middleware/validate.js");
const authController = require("../controller/auth.controller.js");
const { authMiddleware } = require("../middleware/authMiddleware.js");
const { registerValidator, loginValidator } = require('../middleware/validationError.js');
const upload = require("../utils/upload.js");
router.post("/Register", upload.single("profileImage"), registerValidator, validate, authController.Register);
router.post("/login", loginValidator, validate, authController.Login);
router.post("/logout", authMiddleware, authController.Logout);
//router.post("/refreshToken", authController.refreshAccessToken);
module.exports = router;
const express = require('express');
const router = express.Router();
const upload = require("../utils/upload.js");
const userController = require("../controller/user.controller.js");
const validate = require("../middleware/validate.js");
const {
updateUserValidator,
getUserByIdValidator,
deleteUserValidator,
updateStatusValidator,
commentTaskValidator
} = require("../middleware/validationError.js");
const { isAdmin, authMiddleware } = require("../middleware/authMiddleware.js");
router.get("/getAllUser", authMiddleware, isAdmin, userController.getAllUser);
router.get("/getUser/:id", authMiddleware, isAdmin, getUserByIdValidator, validate, userController.getUserById);
router.delete("/deleteUser/:id", authMiddleware, isAdmin, deleteUserValidator, validate, userController.deleteUserById);
router.put("/updateUser/:id", upload.single("profileImage"), authMiddleware, isAdmin, updateUserValidator, validate, userController.updateUserById);
router.patch("/updateTaskStatus/:taskId", authMiddleware, updateStatusValidator, validate, userController.updateStatus);
router.get("/getAllUserTask", authMiddleware, userController.getAllUserTask);
router.put("/commentTask/:taskId", authMiddleware, upload.single('media'), commentTaskValidator, validate, userController.commentTask);
module.exports = router;
const express = require('express');
const router = express.Router();
const taskController = require("../controller/task.controller.js");
const { isAdmin, authMiddleware } = require("../middleware/authMiddleware.js");
const validate = require("../middleware/validate.js");
const {
createTaskValidator,
updateTaskValidator,
taskIdValidator,
assignTaskValidator,
getTaskQueryValidator
} = require("../middleware/validationError.js");
router.post("/createTask", authMiddleware, isAdmin, createTaskValidator, validate, taskController.createTask);
router.get("/getAllTask", authMiddleware, isAdmin, getTaskQueryValidator, validate, taskController.getAllTask);
router.get("/getTask/:id", authMiddleware, isAdmin, taskIdValidator, validate, taskController.getTaskById);
router.delete("/deleteTask/:id", authMiddleware, isAdmin, taskIdValidator, validate, taskController.deleteTaskById);
router.put("/updateTask/:id", authMiddleware, isAdmin, updateTaskValidator, validate, taskController.updateTaskById);
router.put("/softDelete/:id", authMiddleware, isAdmin, taskIdValidator, validate, taskController.softDeleteTask);
router.put("/assignTask/:id", authMiddleware, isAdmin, assignTaskValidator, validate, taskController.assignTask);
module.exports = router;
const User = require("../model/user.model.js");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const Interest = require("../model/interest.model.js");
require('dotenv').config();
// comment when generate access token use
const generateToken = (user) => {
let expiresIn = "1d";
if (user.role === "Admin") expiresIn = "7d";
else if (user.role === "User") expiresIn = "1d";
return jwt.sign(
{ id: user._id, role: user.role },
process.env.SECRET,
{ expiresIn }
);
};
// const generateAccessToken = (user) => {
// let expiresIn = "10h";
// return jwt.sign(
// { id: user._id, role: user.role },
// process.env.ACCESS_SECRET,
// { expiresIn }
// );
// };
// const generateRefreshToken = (user) => {
// let expiresIn = "7d";
// if (user.role === "Admin") {
// expiresIn = "30d";
// } else if (user.role === 'User') {
// expiresIn = "7d"
// }
// return jwt.sign(
// { id: user._id, role: user.role },
// process.env.REFRESH_SECRET,
// { expiresIn }
// );
// };
const Register = async (req, res) => {
try {
const { userName, email, password, role, birthDate, interests } = req.body;
if (role === "Admin") {
const existingAdmin = await User.findOne({ role: "Admin" });
if (existingAdmin) {
return res.status(400).json({ message: "Admin already exists" });
}
}
const isExistingUser = await User.findOne({ email });
if (isExistingUser) {
return res.status(400).json({ message: "User already exists" });
}
const hashedPassword = await bcrypt.hash(password, 10);
let age = null;
if (birthDate && !isNaN(new Date(birthDate).getTime())) {
const dob = new Date(birthDate);
const diff = Date.now() - dob.getTime();
age = new Date(diff).getUTCFullYear() - 1970;
}
const profileImage = req.file ? `/uploads/${req.file.filename}` : "";
const user = new User({
userName,
email,
password: hashedPassword,
role,
birthDate,
age,
profileImage,
sessions: []
});
await user.save();
let interestsArray = [];
if (typeof interests === "string") {
interestsArray = interests.split(",").map(i => i.trim());
} else if (Array.isArray(interests)) {
interestsArray = interests;
}
if (interestsArray.length > 0) {
await Interest.create({
userId: user._id,
name: interestsArray
});
}
res.status(201).json({
message: "User registered successfully",
user: {
id: user._id,
userName: user.userName,
email: user.email,
role: user.role,
age: user.age,
profileImage: user.profileImage,
interests: interestsArray
}
});
} catch (error) {
console.error("Registration error:", error);
res.status(500).json({ message: "Error while registering", error: error.message });
}
};
const Login = async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user) {
return res.status(400).json({ message: "User does not exist." });
}
const matchPassword = await bcrypt.compare(password, user.password);
if (!matchPassword) {
return res.status(400).json({ message: "Invalid Email or Password." });
}
if (user.sessions && user.sessions.length >= 5) {
return res.status(400).json({ message: "Max 5 sessions allowed. Logout from another device." });
}
// comment when generate access token use
const token = generateToken(user);
user.sessions.push({ token, createdAt: new Date() });
await user.save();
res.status(200).json({ message: "Login successful", token });
// const accessToken = generateAccessToken(user);
// const refreshToken = generateRefreshToken(user);
// user.sessions.push({ token: refreshToken, createdAt: new Date() });
//await user.save();
//res.status(200).json({ message: "Login successful", accessToken, refreshToken });
} catch (error) {
console.error("Login error:", error);
res.status(500).json({ message: "Login failed", error: error.message });
}
};
const Logout = async (req, res) => {
try {
// comment when generate access token use
if (!req.user || !req.token) {
return res.status(401).json({ message: "Unauthorized" });
}
req.user.sessions = req.user.sessions.filter(s => s.token !== req.token);
// const { refreshToken } = req.body;
// if (!refreshToken) {
// return res.status(400).json({ message: "Refresh token required" });
// }
// req.user.sessions = req.user.sessions.filter(s => s.token !== refreshToken);
await req.user.save();
res.status(200).json({ message: "User logged out successfully" });
} catch (err) {
res.status(500).json({ message: "Logout failed", error: err.message });
}
};
// const refreshAccessToken = async (req, res) => {
// try {
// const { refreshToken } = req.body;
// if (!refreshToken) {
// return res.status(401).json({ message: "Refresh token required" });
// }
// const jwt = require("jsonwebtoken");
// const decoded = jwt.verify(refreshToken, process.env.REFRESH_SECRET);
// const user = await User.findById(decoded.id);
// if (!user) return res.status(404).json({ message: "User not found" });
// // check refresh token in DB
// const isValid = user.sessions.some(s => s.token === refreshToken);
// if (!isValid) return res.status(401).json({ message: "Invalid refresh token" });
// const newAccessToken = generateAccessToken(user);
// res.json({ accessToken: newAccessToken });
// } catch (err) {
// res.status(401).json({ message: "Invalid or expired refresh token", error: err.message });
// }
// };
module.exports = {
Register,
Login,
Logout,
// refreshAccessToken
};
const User = require("../model/user.model.js");
const jwt = require("jsonwebtoken");
require('dotenv').config();
const authMiddleware = async (req, res, next) => {
try {
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith("Bearer ")) {
return res.status(403).json({ message: "Authorization token missing or invalid" });
}
const token = authHeader.split(" ")[1];
let decoded;
try {
// comment when generate access token use
decoded = jwt.verify(token, process.env.SECRET);
// decoded = jwt.verify(token, process.env.ACCESS_SECRET);
} catch (err) {
return res.status(401).json({ message: "Invalid or expired token" });
}
const user = await User.findById(decoded.id).select("-password");
if (!user) {
return res.status(404).json({ message: "User not found" });
}
// comment when generate access token use
const isSessionValid = user.sessions.some(session => session.token === token);
if (!isSessionValid) {
return res.status(401).json({ message: "Session expired or token not registered" });
}
req.user = user;
req.token = token;
next();
} catch (error) {
console.error("authMiddleware error:", error);
res.status(500).json({ message: "Server error during authentication" });
}
};
const isAdmin = (req, res, next) => {
if (!req.user || req.user.role !== 'Admin') {
return res.status(403).json({ message: "Admin access required" });
}
next();
};
module.exports = { authMiddleware, isAdmin };
const mongoose = require("mongoose");
const User = require("../model/user.model.js");
const Task = require("../model/task.model.js");
const bcrypt = require("bcrypt");
const isValidId = (id) => mongoose.isValidObjectId(id);
const getAllUser = async (req, res) => {
try {
const userName = req.query.userName;
const email = req.query.email;
const limit = parseInt(req.query.limit) || 10;
const page = parseInt(req.query.page) || 1;
const sortBy = req.query.sortBy || 'createdAt';
const orderBy = req.query.orderBy === 'asc' ? 1 : -1;
const skip = (page - 1) * limit;
const query = { role: 'User' };
if (userName) {
query.userName = new RegExp(userName, 'i');
}
if (email) {
query.email = new RegExp(email, 'i');
}
const total = await User.countDocuments(query);
const users = await User.find(query)
.sort({ [sortBy]: orderBy })
.skip(skip)
.limit(limit);
res.status(200).json({
message: "All users fetched successfully",
pageCount: Math.ceil(total / limit),
total,
limit,
data: users
});
} catch (error) {
console.error("Error while getting users:", error);
res.status(500).json({ message: "Server error while getting all users" });
}
};
const getUserById = async (req, res) => {
try {
if (!isValidId(req.params.id)) {
return res.status(400).json({ message: "Invalid user ID" });
}
const user = await User.findById(req.params.id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
res.status(200).json({ message: "User fetched successfully", user });
} catch (error) {
console.error("Error while getting user by id", error);
res.status(500).json({ message: "Server error while getting user" });
}
};
const deleteUserById = async (req, res) => {
try {
if (!isValidId(req.params.id)) {
return res.status(400).json({ message: "Invalid user ID" });
}
const deletedUser = await User.findByIdAndDelete(req.params.id);
if (!deletedUser) {
return res.status(404).json({ message: "User not found" });
}
res.status(200).json({ message: "User deleted successfully", deletedUser });
} catch (error) {
console.error("Error while deleting user", error);
res.status(500).json({ message: "Server error while deleting user" });
}
};
const updateUserById = async (req, res) => {
try {
const { id } = req.params;
const { userName, email, password, role, birthDate } = req.body;
const user = await User.findById(id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
if (role === "Admin") {
const existingAdmin = await User.findOne({ role: "Admin", _id: { $ne: id } });
if (existingAdmin) {
return res.status(400).json({ message: "Another admin already exists" });
}
}
if (email && email !== user.email) {
const existingUser = await User.findOne({ email });
if (existingUser) {
return res.status(400).json({ message: "Email already in use" });
}
user.email = email;
}
if (userName) user.userName = userName;
if (password) {
user.password = await bcrypt.hash(password, 10);
}
if (role) user.role = role;
if (birthDate && !isNaN(new Date(birthDate).getTime())) {
user.birthDate = birthDate;
const dob = new Date(birthDate);
const diff = Date.now() - dob.getTime();
user.age = new Date(diff).getUTCFullYear() - 1970;
}
if (req.file) {
user.profileImage = `/uploads/${req.file.filename}`;
}
await user.save();
res.status(200).json({
message: "User updated successfully",
user: {
id: user._id,
userName: user.userName,
email: user.email,
role: user.role,
age: user.age,
profileImage: user.profileImage
}
});
} catch (error) {
console.error("Update error:", error);
res.status(500).json({ message: "Error while updating user", error: error.message });
}
};
const getAllUserTask = async (req, res) => {
try {
const search = req.query.search || "";
const limit = parseInt(req.query.limit) || 10;
const page = parseInt(req.query.page) || 1;
const sortBy = req.query.sortBy || 'createdAt';
const orderBy = req.query.orderBy === 'asc' ? 1 : -1;
const query = {
'assignTask.userId': req.user.id,
taskName: new RegExp(search, 'i'),
isDeleted: false
};
const total = await Task.countDocuments(query);
const tasks = await Task.find(query)
.populate('createdBy', 'name email')
.sort({ [sortBy]: orderBy })
.skip((page - 1) * limit)
.limit(limit);
res.status(200).json({
message: "Tasks fetched successfully",
tasks,
pageCount: Math.ceil(total / limit),
limit
});
} catch (error) {
console.error("Error while getting user tasks", error);
res.status(500).json({ message: "Server error while fetching tasks" });
}
};
const updateStatus = async (req, res) => {
try {
const { status, id } = req.body;
const { taskId } = req.params;
if (!isValidId(taskId) || !isValidId(id)) {
return res.status(400).json({ message: "Invalid task or assignment ID" });
}
const allowedStatuses = ["Pending", "In Progress", "Completed"];
if (!status || !allowedStatuses.includes(status)) {
return res.status(400).json({ message: "Invalid status value" });
}
const task = await Task.findOneAndUpdate(
{ _id: taskId, 'assignTask._id': id, 'assignTask.userId': req.user.id },
{ $set: { 'assignTask.$.status': status } },
{ new: true }
);
if (!task) {
return res.status(404).json({ message: "Task not found or not assigned to you" });
}
res.status(200).json({ message: "Task status updated successfully", task });
} catch (error) {
console.error("Error while updating task status", error);
res.status(500).json({ message: "Server error while updating task status" });
}
};
const commentTask = async (req, res) => {
try {
const { taskId } = req.params;
const { comment } = req.body;
const userId = req.user.id;
if (!isValidId(taskId)) {
return res.status(400).json({ message: "Invalid task ID" });
}
if (!comment && !req.file) {
return res.status(400).json({ message: "Comment or file is required" });
}
const filePath = req.file ? `/uploads/${req.file.filename}` : null;
const task = await Task.findOneAndUpdate(
{ _id: taskId, 'assignTask.userId': userId },
{
$push: {
comments: {
userId,
media: filePath,
comment
}
}
},
{ new: true }
);
if (!task) {
return res.status(404).json({ message: "Task not found or not assigned to you" });
}
res.status(200).json({ message: "Comment added successfully", task });
} catch (error) {
console.error("Error while adding comment", error);
res.status(500).json({ message: "Server error while adding comment" });
}
};
module.exports = {
deleteUserById,
updateUserById,
getAllUser,
getUserById,
updateStatus,
getAllUserTask,
commentTask
};
const mongoose = require("mongoose");
const Task = require("../model/task.model.js");
const User = require("../model/user.model.js");
const sendHtmlMail = require("../utils/mail.js");
const path = require("path");
const createTask = async (req, res) => {
try {
const { taskName, description } = req.body;
if (!taskName || !description) {
return res.status(400).json({ message: "Task name and description are required" });
}
const isTask = await Task.findOne({ taskName: { $regex: `^${taskName}$`, $options: "i" } });
if (isTask) {
return res.status(400).json({ message: "Task already exists" });
}
const task = new Task({
taskName,
description,
createdBy: req.user.id
});
await task.save();
res.status(201).json({ message: "Task created successfully", task });
} catch (error) {
console.error("Error while creating task:", error);
res.status(500).json({ message: "Error while creating task", error: error.message });
}
};
const getAllTask = async (req, res) => {
try {
const taskName = req.query.taskName || "";
const limit = parseInt(req.query.limit) || 10;
const page = parseInt(req.query.page) || 1;
const sortBy = req.query.sortBy || "createdAt";
const orderBy = req.query.orderBy === "asc" ? 1 : -1;
const query = { isDeleted: false };
if (taskName) {
query.taskName = new RegExp(taskName, "i");
}
const total = await Task.countDocuments(query);
const tasks = await Task.find(query)
.populate("createdBy", "name email")
.sort({ [sortBy]: orderBy })
.skip((page - 1) * limit)
.limit(limit);
res.status(200).json({
message: "Tasks fetched successfully",
tasks,
pageCount: Math.ceil(total / limit),
total
});
} catch (error) {
console.error("Error while fetching tasks:", error);
res.status(500).json({ message: "Error while fetching tasks", error: error.message });
}
};
const getTaskById = async (req, res) => {
try {
if (!mongoose.Types.ObjectId.isValid(req.params.id)) {
return res.status(400).json({ message: "Invalid task ID" });
}
const task = await Task.findOne({ _id: req.params.id, isDeleted: false });
if (!task) {
return res.status(404).json({ message: "Task not found" });
}
res.status(200).json({ message: "Task fetched successfully", task });
} catch (error) {
console.error("Error while getting task by ID:", error);
res.status(500).json({ message: "Error while getting task by ID", error: error.message });
}
};
const deleteTaskById = async (req, res) => {
try {
if (!mongoose.Types.ObjectId.isValid(req.params.id)) {
return res.status(400).json({ message: "Invalid task ID" });
}
const deletedTask = await Task.findByIdAndDelete(req.params.id);
if (!deletedTask) {
return res.status(404).json({ message: "Task not found" });
}
res.status(200).json({ message: "Task deleted successfully", deletedTask });
} catch (error) {
console.error("Error while deleting task:", error);
res.status(500).json({ message: "Error while deleting task", error: error.message });
}
};
const updateTaskById = async (req, res) => {
try {
if (!mongoose.Types.ObjectId.isValid(req.params.id)) {
return res.status(400).json({ message: "Invalid task ID" });
}
const updatedTask = await Task.findOneAndUpdate(
{ _id: req.params.id, isDeleted: false },
req.body,
{ new: true }
);
if (!updatedTask) {
return res.status(404).json({ message: "Task not found or already deleted" });
}
res.status(200).json({ message: "Task updated successfully", updatedTask });
} catch (error) {
console.error("Error while updating task:", error);
res.status(500).json({ message: "Error while updating task", error: error.message });
}
};
const softDeleteTask = async (req, res) => {
try {
if (!mongoose.Types.ObjectId.isValid(req.params.id)) {
return res.status(400).json({ message: "Invalid task ID" });
}
const task = await Task.findByIdAndUpdate(req.params.id, { isDeleted: true }, { new: true });
if (!task) {
return res.status(404).json({ message: "Task not found" });
}
res.status(200).json({ message: "Task soft-deleted successfully", task });
} catch (error) {
console.error("Error while soft-deleting task:", error);
res.status(500).json({ message: "Error while soft-deleting task", error: error.message });
}
};
const assignTask = async (req, res) => {
try {
const { userIds } = req.body;
if (!Array.isArray(userIds) || userIds.length === 0) {
return res.status(400).json({ message: "User IDs are required and must be an array" });
}
const users = await User.find({ _id: { $in: userIds }, role: "User" });
if (userIds.length !== users.length) {
return res.status(400).json({ message: "One or more user IDs are invalid or not 'User' role" });
}
const task = await Task.findOne({ _id: req.params.id, isDeleted: false });
if (!task) {
return res.status(404).json({ message: "Task not found or already deleted" });
}
const alreadyAssigned = task.assignTask.map(a => a.userId.toString());
const newUsers = users.filter(user => !alreadyAssigned.includes(user._id.toString()));
if (newUsers.length === 0) {
return res.status(400).json({ message: "All provided users are already assigned to this task" });
}
const validUsers = newUsers.map(user => ({
userId: user._id,
status: "Pending",
}));
task.assignTask.push(...validUsers);
await task.save();
res.status(200).json({ message: "Task assigned successfully", task });
} catch (error) {
console.error("Error while assigning task:", error);
res.status(500).json({ message: "Error while assigning task", error: error.message });
}
};
module.exports = {
createTask,
getTaskById,
updateTaskById,
deleteTaskById,
getAllTask,
softDeleteTask,
assignTask,
}
const { validationResult } = require('express-validator');
const validate = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
}
module.exports = validate;
const { body, param, query } = require("express-validator");
exports.registerValidator = [
body('userName')
.notEmpty().withMessage('User name is required')
.isLength({ min: 3 }).withMessage('User name must be at least 3 characters long'),
body('email')
.isEmail().withMessage('Valid email is required'),
body('password')
.isLength({ min: 6 }).withMessage('Password must be at least 6 characters long'),
body('role')
.isIn(['Admin', 'User']).withMessage('Role must be either Admin or User'),
];
exports.loginValidator = [
body('email')
.isEmail().withMessage('Valid email is required'),
body('password')
.notEmpty().withMessage('Password is required')
];
exports.updateUserValidator = [
param('id').isMongoId().withMessage("Invalid user ID"),
body('userName').optional().isLength({ min: 3 }).withMessage("User name must be at least 3 characters"),
body('email').optional().isEmail().withMessage("Valid email is required"),
body('password').optional().isLength({ min: 6 }).withMessage("Password must be at least 6 characters"),
];
exports.getUserByIdValidator = [
param('id').isMongoId().withMessage("Invalid user ID")
];
exports.deleteUserValidator = [
param('id').isMongoId().withMessage("Invalid user ID")
];
exports.updateStatusValidator = [
param('taskId').isMongoId().withMessage("Invalid Task ID"),
body('id').isMongoId().withMessage("Invalid Assign Task ID"),
body('status').isIn(['Pending', 'Ongoing', 'Completed']).withMessage("Invalid status value"),
];
exports.commentTaskValidator = [
param('taskId').isMongoId().withMessage("Invalid Task ID"),
body('comment').notEmpty().withMessage("Comment is required")
];
exports.createTaskValidator = [
body("taskName")
.notEmpty().withMessage("Task name is required")
.isLength({ min: 3 }).withMessage("Task name must be at least 3 characters"),
body("description")
.notEmpty().withMessage("Description is required")
];
exports.updateTaskValidator = [
param("id").isMongoId().withMessage("Invalid Task ID"),
body("taskName").optional().isLength({ min: 3 }).withMessage("Task name must be at least 3 characters"),
body("description").optional().isLength({ min: 3 }).withMessage("Description must be at least 3 characters")
];
exports.taskIdValidator = [
param("id").isMongoId().withMessage("Invalid Task ID")
];
exports.assignTaskValidator = [
param("id").isMongoId().withMessage("Invalid Task ID"),
body("userIds")
.isArray({ min: 1 }).withMessage("userIds must be a non-empty array")
.custom((arr) => arr.every(id => typeof id === "string")).withMessage("Each userId must be a string")
];
exports.getTaskQueryValidator = [
query("limit").optional().isInt({ min: 1 }).withMessage("limit must be a positive number"),
query("page").optional().isInt({ min: 1 }).withMessage("page must be a positive number"),
query("sortBy").optional().isString().withMessage("sortBy must be a string"),
query("orderBy").optional().isIn(["asc", "desc"]).withMessage("orderBy must be 'asc' or 'desc'")
];
const nodemailer = require("nodemailer");
const ejs = require("ejs");
const transporter = nodemailer.createTransport({
host: "smtp.mailtrap.io",
port: 587,
auth: {
user: "47e27c7dace3d1",
pass: "4afd701b115d55",
},
});
const sendHtmlMail = async (to, subject, templatePath, data) => {
try {
const html = await ejs.renderFile(templatePath, data);
const mailOptions = {
from: '"Task System" <no-reply@task.com>',
to,
subject,
html,
};
const result = await transporter.sendMail(mailOptions);
console.log("Email sent:", result.messageId);
return result;
} catch (err) {
console.error(" Failed to send email:", err.message);
throw err;
}
};
module.exports = sendHtmlMail;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>New Task Assigned</title>
<style>
body { font-family: Arial, sans-serif; color: #333; }
.container { padding: 20px; background: #f9f9f9; border-radius: 10px; }
h2 { color: #007bff; }
</style>
</head>
<body>
<div class="container">
<h2>Hello <%= userName %>,</h2>
<p>You have been assigned a new task:</p>
<ul>
<li><strong>Task Name:</strong> <%= taskName %></li>
<li><strong>Description:</strong> <%= description %></li>
</ul>
<p>Please check your task list in the system.</p>
<br>
<p>Thanks,<br/>Task Management Team</p>
</div>
</body>
</html>