-
Notifications
You must be signed in to change notification settings - Fork 0
API created for Leave #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "dependencies": { | ||
| "bcryptjs": "^3.0.3" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,128 @@ | ||||||||||||||||||||||||||||||||
| import Employee from "../models/Employee.js"; | ||||||||||||||||||||||||||||||||
| import LeaveApplication from "../models/LeaveApplication.js"; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| //Create leave | ||||||||||||||||||||||||||||||||
| //POST /api/leave | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| export const createLeave = async (req, res) => { | ||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||
| const session = req.session; | ||||||||||||||||||||||||||||||||
| const employee = await Employee.findOne({ userId: session.userId }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!employee) | ||||||||||||||||||||||||||||||||
| return res.status(404).json({ message: "Employee not found" }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (employee.isDeleted) | ||||||||||||||||||||||||||||||||
| return res.status(403).json({ message: "Your account id deactivated.You cannot create leave" }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const { type, startDate, endDate, reason } = req.body; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!type || !startDate || !endDate || !reason) | ||||||||||||||||||||||||||||||||
| return res.status(400).json({ message: "Please provide all the required fields" }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const today = new Date(); | ||||||||||||||||||||||||||||||||
| today.setHours(0, 0, 0, 0); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (new Date(startDate) < today || new Date(endDate) < today) | ||||||||||||||||||||||||||||||||
| return res.status(400).json({ message: "Please provide valid dates" }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (new Date(endDate) < today || new Date(startDate) < today) | ||||||||||||||||||||||||||||||||
| return res.status(400).json({ message: "end date must be greater than start date" }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const leave = await LeaveApplication.create({ | ||||||||||||||||||||||||||||||||
| employeeId: employee._id, | ||||||||||||||||||||||||||||||||
| type, | ||||||||||||||||||||||||||||||||
| startDate: new Date(startDate), | ||||||||||||||||||||||||||||||||
| endDate: new Date(endDate), | ||||||||||||||||||||||||||||||||
| reason, | ||||||||||||||||||||||||||||||||
| status: "PENDING" | ||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return res.json({ | ||||||||||||||||||||||||||||||||
| success: true, | ||||||||||||||||||||||||||||||||
| data: leave | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||
| console.log(error); | ||||||||||||||||||||||||||||||||
| return res.status(500).json({ error: "Failed to create leave" }); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| //Get leave | ||||||||||||||||||||||||||||||||
| //GET /api/leaves | ||||||||||||||||||||||||||||||||
| export const getLeaves = async (req, res) => { | ||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||
| const session = req.session; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const isAdmin = session.role === "ADMIN"; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (isAdmin) { | ||||||||||||||||||||||||||||||||
| const status = req.query.status; | ||||||||||||||||||||||||||||||||
| const where = status ? { status } : {} | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const leaves = await LeaveApplication.find(where). | ||||||||||||||||||||||||||||||||
| populate("employeeId").sort({ createdAt: -1 }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const data = leaves.map((l) => { | ||||||||||||||||||||||||||||||||
| const obj = l.toObject(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||
| ...obj, | ||||||||||||||||||||||||||||||||
| id: obj._id.toString(), | ||||||||||||||||||||||||||||||||
| employee: obj.employeeId, | ||||||||||||||||||||||||||||||||
| employeeId: obj.employeeId?._id?.toString() | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return res.json({ | ||||||||||||||||||||||||||||||||
| data | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||
| const employee = await Employee.findOne({ userId: session.userId }).lean(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!employee) | ||||||||||||||||||||||||||||||||
| return res.status(404).json({ error: "Not Found" }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const leaves = await LeaveApplication.find({ | ||||||||||||||||||||||||||||||||
| employeeId: employee._id | ||||||||||||||||||||||||||||||||
| }).sort({ createdAt: -1 }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return res.json({ | ||||||||||||||||||||||||||||||||
| data: leaves, | ||||||||||||||||||||||||||||||||
| employee: { ...employee, id: employee._id.toString() } | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||
| console.log(error); | ||||||||||||||||||||||||||||||||
| return res.status(500).json({ error: "Failed to fetch leaves" }); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| //Update leave status | ||||||||||||||||||||||||||||||||
| //PATCH /api/leaves/:id | ||||||||||||||||||||||||||||||||
| export const updateLeaveStatus = async (req, res) => { | ||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||
| const { status } = req.body; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (!["AP[ROVED", "REJECTED", "PENDING"].includes(status)) | ||||||||||||||||||||||||||||||||
| return res.status(400).json({ error: "invalid status" }); | ||||||||||||||||||||||||||||||||
|
Comment on lines
+113
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical typo: This typo causes all legitimate "APPROVED" status updates to be rejected with "invalid status" error. 🐛 Proposed fix- if (!["AP[ROVED", "REJECTED", "PENDING"].includes(status))
+ if (!["APPROVED", "REJECTED", "PENDING"].includes(status))
return res.status(400).json({ error: "invalid status" });📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| const leave = await LeaveApplication.findByIdAndUpdate(req.params.id, { status }, { returnDocument: 'after' }); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| return res.json({ | ||||||||||||||||||||||||||||||||
| success: true, | ||||||||||||||||||||||||||||||||
| data: leave | ||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||
|
Comment on lines
+117
to
+122
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing null check when leave is not found. If 🐛 Proposed fix const leave = await LeaveApplication.findByIdAndUpdate(req.params.id, { status }, { returnDocument: 'after' });
+ if (!leave)
+ return res.status(404).json({ error: "Leave application not found" });
+
return res.json({
success: true,
data: leave
})📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||
| return res.status(500).json({ error: "Failed" }); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,37 @@ | ||||||||||||||||||||||||||||||||||||||||||||||
| import mongoose from "mongoose"; | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const leaveApplicationSchema = new mongoose.Schema({ | ||||||||||||||||||||||||||||||||||||||||||||||
| employeeId: { | ||||||||||||||||||||||||||||||||||||||||||||||
| type: mongoose.Schhema.Types.ObjectId, | ||||||||||||||||||||||||||||||||||||||||||||||
| ref: "Employee", | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+6
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify the typo and expected Schema API usage
rg -n 'Schhema|Schema\.Types\.ObjectId' server/models/LeaveApplication.jsRepository: harshGupta090722/EMS Length of output: 113 Fix typo in ObjectId type definition— Line 7 uses Proposed fix- type: mongoose.Schhema.Types.ObjectId,
+ type: mongoose.Schema.Types.ObjectId,📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| required: true, | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| type: { | ||||||||||||||||||||||||||||||||||||||||||||||
| type: String, | ||||||||||||||||||||||||||||||||||||||||||||||
| enum: ["SICK", "CASUAL", "ANNUAL"], | ||||||||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| startDate: { | ||||||||||||||||||||||||||||||||||||||||||||||
| type: Date, | ||||||||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| endDate: { | ||||||||||||||||||||||||||||||||||||||||||||||
| type: Date, | ||||||||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+16
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add date-order validation for leave periods.
Proposed fix endDate: {
type: Date,
- required: true
+ required: true,
+ validate: {
+ validator: function (value) {
+ return !this.startDate || value >= this.startDate;
+ },
+ message: "endDate must be greater than or equal to startDate"
+ }
},📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||
| reason: { | ||||||||||||||||||||||||||||||||||||||||||||||
| type: String, | ||||||||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||
| status: { | ||||||||||||||||||||||||||||||||||||||||||||||
| type: String, | ||||||||||||||||||||||||||||||||||||||||||||||
| enum: ["PENDING", "APPROVED", "REJECTED"], | ||||||||||||||||||||||||||||||||||||||||||||||
| default: "PENDING" | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| const LeaveApplication = mongoose.model("LeaveApplication", leaveApplicationSchema); | ||||||||||||||||||||||||||||||||||||||||||||||
| export default LeaveApplication; | ||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical bug: Date validation logic is incorrect and duplicated.
Lines 29-30 have the same condition as lines 26-27, making the second check unreachable and failing to validate that
endDate >= startDate. Users can submit a leave whereendDateis beforestartDate.🐛 Proposed fix
if (new Date(startDate) < today || new Date(endDate) < today) return res.status(400).json({ message: "Please provide valid dates" }); - if (new Date(endDate) < today || new Date(startDate) < today) + if (new Date(endDate) < new Date(startDate)) return res.status(400).json({ message: "end date must be greater than start date" });🤖 Prompt for AI Agents