Student Controller
Overview
The StudentController handles student-related functionalities including profile data, course enrollments, document applications, announcements, and course drop operations. It facilitates both student self-service and admin operations through a well-structured set of endpoints.
Dependencies
import { Student } from '../models/student.model.js';
import { Course, StudentCourse, FacultyCourse } from '../models/course.model.js';
import { ApplicationDocument, Bonafide, Passport } from '../models/documents.models.js';
import { Faculty } from '../models/faculty.model.js';
import { CourseDropRequest } from '../models/courseDropRequest.model.js';
import { User } from '../models/user.model.js';`
Controller Methods
Student Data
getStudent
Fetches the profile of a specific student.
Input:
- req.params.id: Student userId
Process:
1. Finds student by userId
2. Populates the associated User document
Key Code Snippet
const studentId = req.params.id;
const user = await Student.findOne({ userId: studentId })
.populate('userId');
if (!user) {
return res.status(404).json({ message: 'Student not found' });
}
Output: - Success (200): Returns student document - Error (404/500): Appropriate error message
updateStudentProfile
Updates profile information for a student.
Input:
- req.params.id: Student userId
- req.body: Profile update data
Process:
1. Updates user fields (name, email, contactNo) if present
2. Updates student model (hostel, roomNo, department, etc.)
Key Code Snippet
if (updateData.userData) {
await User.findByIdAndUpdate(
updateData.userData.userId,
{
name: updateData.userData.name,
email: updateData.userData.email,
contactNo: updateData.userData.contact
}
);
}
const student = await Student.findOneAndUpdate(
{ userId: studentId },
{
hostel: updateData.hostel,
roomNo: updateData.roomNo,
department: updateData.branch,
program: updateData.program,
semester: updateData.semester,
updatedAt: new Date()
},
{ new: true }
).populate('userId');
Output: - Success (200): Updated student document - Error (404/500): Error message
getStudentFromRollNumber
Finds the student's userId using their roll number.
Input:
- req.params.id: Student's rollNo
Process:
1. Searches Student model using rollNo
Key Code Snippet
const rollNo = req.params.id;
const student = await Student.findOne({ rollNo: rollNo });
if (!student) {
return res.status(404).json({ message: 'Student not found' });
}
Output:
- Success (200): Returns userId
- Error (404/500): Error message
Academic Courses
getCompletedCourses
Fetches completed courses for a student.
Input:
- req.params.id: Student userId
Process:
1. Retrieves StudentCourse entries with isCompleted: true
2. Fetches course metadata using courseCode
3. Merges course and performance data
Key Code Snippet
const user = await Student.findOne({ userId: req.params.id })
.populate('userId');
const studentCourses = await StudentCourse.find({
rollNo: user.rollNo,
isCompleted: true
}).lean();
const courseIds = studentCourses.map(sc => sc.courseId);
const courseDetails = await Course.find({
courseCode: { $in: courseIds }
}).lean();
Output: - Success (200): Array of completed courses - Error (404/500): Error message
getStudentCourses
Retrieves current approved courses for a student.
Input:
- req.params.id: Student userId
Process:
1. Determines session based on current date
2. Fetches approved StudentCourse records
3. Merges with course data and faculty assignments
Key Code Snippet
const student = await Student.findOne({ userId: studentId });
const studentCourses = await StudentCourse.find({ rollNo: student.rollNo, status: 'Approved' });
const courses = await Promise.all(
studentCourses.map(async (sc) => {
const course = await Course.findOne({ courseCode: sc.courseId });
if (!course) return null;
return {
id: course.courseCode,
name: course.courseName,
credits: course.credits,
assignments: 8,
announcements: course.announcements.length,
attendance: 85
};
})
);
Output: - Success (200): Array of current course objects - Error (404/500): Appropriate message
dropCourse
Removes a course from the student's profile.
Input:
- req.params.studentId: Student ID
- req.params.courseId: Course ID
Process: 1. Validates student enrollment 2. Removes course from student and course models
Key Code Snippet
const student = await Student.findById(studentId);
const courseIndex = student.courses.findIndex(course => course.toString() === courseId);
if (courseIndex === -1) {
return res.status(404).json({ message: "Course not found in student's enrolled courses" });
}
student.courses.splice(courseIndex, 1);
await student.save();
Output: - Success (200): Confirmation message - Error (404): Course or student not found
createCourseDropRequest
Submits a drop request for an enrolled course.
Input:
- req.params.id: Student userId
- req.body.courseId: Course code
Process:
1. Checks enrollment and pending drop requests
2. Constructs a CourseDropRequest with Pending status
Key Code Snippet
const student = await Student.findOne({ userId: studentId });
const studentCourse = await StudentCourse.findOne({
rollNo: student.rollNo,
courseId: courseId,
status: 'Approved'
});
const dropRequest = new CourseDropRequest({
studentId: studentId,
rollNo: student.rollNo,
courseId: courseId,
courseName: course.courseName,
semester: semester,
status: 'Pending'
});
await dropRequest.save();
Output: - Success (201): Confirmation and request ID - Error (400/404/500): Proper error handling
getStudentDropRequests
Fetches all course drop requests for a student.
Input:
- req.params.id: Student userId
Process:
1. Retrieves CourseDropRequest by rollNo
2. Sorts by most recent
Key Code Snippet
const student = await Student.findOne({ userId: studentId });
const dropRequests = await CourseDropRequest.find({
rollNo: student.rollNo
}).sort({ createdAt: -1 });
Output: - Success (200): Array of drop requests - Error (404/500): Error message
cancelDropRequest
Cancels a pending course drop request.
Input:
- req.params.id: Student userId
- req.params.requestId: Drop request ID
Process: 1. Verifies ownership and pending status 2. Deletes the request
Key Code Snippet
const student = await Student.findOne({ userId: studentId });
const dropRequest = await CourseDropRequest.findById(requestId);
if (dropRequest.rollNo !== student.rollNo) {
return res.status(403).json({ message: 'Unauthorized to cancel this request' });
}
await CourseDropRequest.findByIdAndDelete(requestId);
Output: - Success (200): Confirmation - Error (400/403/404/500): Validated errors
Course Announcements
getCourseAnnouncements
Fetches course announcements along with faculty details.
Input:
- req.params.courseId: Course code
Process: 1. Retrieves course and announcement list 2. Enriches each announcement with faculty metadata 3. Sorts by latest
Key Code Snippet
const course = await Course.findOne({ courseCode: courseId });
const facultyIds = [...new Set(course.announcements.map(announcement => announcement.postedBy))];
const facultyMembers = await Faculty.find({ facultyId: { $in: facultyIds } });
const announcementsWithFaculty = course.announcements.map(announcement => {
const faculty = facultyLookup[announcement.postedBy] || null;
return { ...announcement.toObject(), faculty };
});
Output: - Success (200): Course document with enhanced announcements - Error (404/500): Error message
getFacultyByIds
Retrieves a list of faculty by their IDs.
Input:
- req.query.ids: Comma-separated faculty IDs
Process:
1. Queries Faculty model using $in filter
Key Code Snippet
const facultyIds = req.query.ids.split(',');
const facultyMembers = await Faculty.find({ facultyId: { $in: facultyIds } });
Output: - Success (200): Array of faculty documents - Error (404/500): Error message
Bonafide Certificate
getStudentBonafideDetails
Returns student profile data for bonafide application.
Input:
- req.params.id: Student userId
Process: 1. Populates basic user details 2. Maps required student fields
Key Code Snippet
const student = await Student.findOne({ userId: studentId })
.populate('userId', 'name dateOfBirth');
const studentDetails = {
name: student.userId.name,
rollNo: student.rollNo,
fatherName: student.fatherName,
dateOfBirth: student.userId.dateOfBirth,
program: student.program,
department: student.department,
hostel: student.hostel,
roomNo: student.roomNo,
semester: student.semester,
batch: student.batch,
enrolledYear: student.batch
};
Output:
- Success (200): Returns data for bonafide application
- Error (404/500): Error message
createBonafideApplication
Submits a new bonafide application.
Input:
- req.params.id: Student userId
- req.body: Includes currentSemester, certificateFor, otherReason
Process:
1. Creates ApplicationDocument and Bonafide records
2. Handles conditional reason fields
Key Code Snippet
const applicationDoc = new ApplicationDocument({
studentId: student._id,
documentType: 'Bonafide',
status: 'Pending'
});
await applicationDoc.save();
const bonafide = new Bonafide({
applicationId: applicationDoc._id,
currentSemester,
purpose: certificateFor,
otherReason: certificateFor === 'Other' ? otherReason : undefined
});
await bonafide.save();
Output: - Success (201): Application ID - Error (404/500): Error message
getBonafideApplications
Returns all bonafide applications submitted by a student.
Input:
- req.params.id: Student userId
Process:
1. Queries documents of type Bonafide
2. Enriches with bonafide-specific data
Key Code Snippet
const applications = await ApplicationDocument.find({
studentId: student._id,
documentType: 'Bonafide'
}).sort({ createdAt: -1 });
const applicationDetails = await Promise.all(applications.map(async (app) => {
const bonafide = await Bonafide.findOne({ applicationId: app._id });
if (!bonafide) return null;
return {
applicationDate: app.createdAt,
certificateFor: bonafide.purpose === 'Other' ? bonafide.otherReason : bonafide.purpose,
currentSemester: bonafide.currentSemester,
remarks: app.approvalDetails?.remarks || '',
documentStatus: app.status === 'Pending' ? 'Documents Under Review' : 'Documents Verified',
currentStatus: app.status
};
}));
Output: - Success (200): Array of applications - Error (404/500): Error message
Passport Certificate
getStudentPassportDetails
Fetches student information for passport application.
Input:
- req.params.id: Student userId
Process: 1. Fetches student and user profile fields
Key Code Snippet
const student = await Student.findOne({ userId: studentId })
.populate('userId', 'name dateOfBirth email');
const studentDetails = {
name: student.userId.name,
rollNo: student.rollNo,
department: student.department,
programme: student.program,
dateOfBirth: student.userId.dateOfBirth,
email: student.userId.email,
contactNumber: student.userId.contactNo || '',
hostelName: student.hostel,
roomNo: student.roomNo,
fathersName: student.fatherName,
mothersName: student.motherName
};
Output: - Success (200): Populated profile object - Error (404/500): Error message
submitPassportApplication
Creates a passport application entry.
Input:
- req.params.id: Student userId
- req.body: Includes applicationType, placeOfBirth, semester, etc.
Process:
1. Creates ApplicationDocument
2. Creates associated Passport document
Key Code Snippet
const applicationDoc = new ApplicationDocument({
studentId: student._id,
documentType: 'Passport',
status: 'Pending'
});
await applicationDoc.save();
const passport = new Passport({
applicationId: applicationDoc._id,
applicationType,
placeOfBirth,
semester,
mode,
tatkalReason,
travelPlans,
travelDetails,
fromDate: travelPlans === 'yes' ? fromDate : undefined,
toDate: travelPlans === 'yes' ? toDate : undefined
});
await passport.save();
Output: - Success (201): Application ID - Error (404/500): Error message
getPassportApplications
Lists all passport applications for a student.
Input:
- req.params.id: Student userId
Process:
1. Retrieves ApplicationDocument of type Passport
2. Fetches and maps associated Passport data
Key Code Snippet
const applications = await ApplicationDocument.find({
studentId: student._id,
documentType: 'Passport'
}).sort({ createdAt: -1 }).lean();
const passportApplications = await Promise.all(
applications.map(async (app) => {
const passportDoc = await Passport.findOne({ applicationId: app._id });
return {
applicationDate: new Date(app.createdAt).toLocaleString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
}),
applicationType: passportDoc.applicationType,
mode: passportDoc.mode,
remarks: app.approvalDetails?.remarks || '',
otherDetails: passportDoc.mode === 'tatkal' ? `Tatkal Application - ${passportDoc.tatkalReason}` : 'Regular Application',
documentStatus: app.status === 'Pending' ? 'Documents Under Review' : 'Documents Verified',
currentStatus: app.status
};
})
);
Output: - Success (200): Array of passport applications - Error (404/500): Error message
Error Handling Strategy
- All endpoints validate required fields and return specific error messages
- Logs detailed errors to the console
- Differentiates between
404,400, and500errors for clarity
Security Considerations
- Authentication & Authorization:
- Assumes upstream middleware handles session validation
- Validation:
- Every endpoint validates inputs before accessing the database
- Sensitive Data:
- Only public student info is exposed; passwords and secure fields are omitted