Skip to content

Commit

Permalink
Merge pull request #100 from uwidcit/Nicholas-Smith_Branch
Browse files Browse the repository at this point in the history
Nicholas smith branch
  • Loading branch information
firepenguindisopanda authored Sep 12, 2024
2 parents 516f55b + cd8b298 commit 033756f
Show file tree
Hide file tree
Showing 16 changed files with 638 additions and 189 deletions.
3 changes: 2 additions & 1 deletion config/corsOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ const allowedOrigins = require('./allowedOrigins');

const corsOptions = {
origin: (origin, callback) => {
if (origin && origin.startsWith(allowedOrigins)) {
console.log('origin: ', origin);
if (origin && allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Not allowed by CORS'));
Expand Down
2 changes: 1 addition & 1 deletion controllers/getDegreeProgress.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const { Op } = require("sequelize");
// returns the students degree progress(list of completed courses, total credits completed, remaining requirements and total credits remaining)
async function getDegreeProgress(student_id) {
try {
let invalid_grades = ["F1", "F2", "F3", "DIS", "EI", "FA", "FAS", "FC", "FE", "FO", "FP", "FT", "FWS", "FTS", "AB", "AM", "AMS", "DB", "DEF", "EQ", "EX", "FM", "FMS", "FWR", "I", "IP", "LW", "NCR", "NFC", "NP", "NR", "NV", "W", "FMP"]
let invalid_grades = ["F1", "F2", "F3", "DIS", "EI", "FA", "FAS", "FC", "FE", "FO", "FP", "FT", "FWS", "FTS", "AB", "AM", "AMS", "DB", "DEF", "EQ", "FM", "FMS", "FWR", "I", "IP", "LW", "NCR", "NFC", "NP", "NR", "NV", "W", "FMP"]
let studentCourseCodes = await StudentCourse.findAll({
attributes: ['courseCode', 'grade'],
where: {
Expand Down
228 changes: 170 additions & 58 deletions controllers/getStudentCoursePlan.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
const AdvisingSession = require("../models/AdvisingSession");
const Student = require("../models/Student");
const SelectedCourse = require("../models/SelectedCourse")
const SelectedCourse = require("../models/SelectedCourse");
const StudentCourse = require("../models/StudentCourse");
const Course = require("../models/Course");
const ProgrammeCourse = require("../models/ProgrammeCourse");
const Type = require("../models/Type");
const ElectiveRequirement = require("../models/ElectiveRequirement");
const { getCoursePlan } = require("./getCoursePlan");
const { Op, where } = require('sequelize');
async function getStudentCoursePlan(studentId,semesterId){
try{
async function getStudentCoursePlan(studentId, semesterId) {

try {
const advising_info = await AdvisingSession.findOne({
attributes: ['planStatus', 'updatedAt'],
where: {
[Op.and] : [
{studentId: studentId},
{semesterId:semesterId}
[Op.and]: [
{ studentId: studentId },
{ semesterId: semesterId }
]

}
});

Expand All @@ -24,7 +29,7 @@ async function getStudentCoursePlan(studentId,semesterId){
const day = String(current_date.getDate()).padStart(2, '0');
let last_update = `${year}-${month}-${day}`;
let status = "New";
if(advising_info){
if (advising_info) {
last_update = advising_info.get('updatedAt');
status = advising_info.get('planStatus');
}
Expand All @@ -38,60 +43,167 @@ async function getStudentCoursePlan(studentId,semesterId){
}
} catch (error) {
const msg = `Error in getting student's ${studentId} structured courseplan for semesterId ${semesterId}:`;
console.log(msg, {...error});
console.log(msg, { ...error });
return null;
}
}
//Pretty Redundant
async function getStudentCoursePlanSimple(studentId,semesterId){
try{
const courseplan = await AdvisingSession.findOne({
attributes: ['studentId','planStatus','id'],
where: {
[Op.and] :[
{studentId:studentId},
{semesterId:semesterId}
]
}
}).then(async (plan)=>{
const current_year = new Date().getFullYear();
const year = current_year - await Student.findOne({
attributes:['year'],
where :{
studentId: studentId
}
}).then(async(stu)=>{
return stu.get('year');
});
if(!plan){
let status = "New";
return{
year:year,
status: status,
courses:[]


async function getStudentCoursePlanByStudentIdAndSemesterId(studentId, semesterId) {

try {
// Fetch the student to get their programmeId
const student = await Student.findByPk(studentId, {
attributes: ['programmeId']
});

if (!student) {
throw new Error("Student not found.");
}
// Fetch the advising session for the student and semester
const advisingSession = await AdvisingSession.findOne({
where: { studentId, semesterId },
attributes: ['updatedAt', 'planStatus']
});

if (!advisingSession) {
throw new Error("No advising session found for the given student and semester.");
}

// Fetch the selected courses for the advising session
const selectedCourses = await SelectedCourse.findAll({
include: [
{
model: AdvisingSession,
where: {
studentId: studentId,
semesterId: semesterId
},
attributes: []
},
{
model: Course,
attributes: ['code', 'title', 'credits'],
include: [{
model: ProgrammeCourse,
where: { programmeId: student.programmeId },
attributes: ['typeId'],
include: [{
model: Type,
attributes: ['type']
}]
}]
}
],
attributes: []
});

// Fetch the completed courses for the student in the semester
const studentCourses = await StudentCourse.findAll({
where: {
studentId: studentId,
},
include: [{
model: Course,
attributes: ['code', 'title', 'credits'],
include: [{
model: ProgrammeCourse,
where: { programmeId: student.programmeId },
attributes: ['typeId'],
include: [{
model: Type,
attributes: ['type']
}]
}]
}],
attributes: []
});


// Transform the data
const completedCourseData = studentCourses.map(sc => ({
courseCode: sc.course.code,
courseTitle: sc.course.title,
credits: sc.course.credits,
type: sc.course.programmeCourses[0]?.type?.type || 'Unknown',
selected: false,
completed: true
}));


const selectedCourseData = selectedCourses.map(sc => ({
courseCode: sc.course.code,
courseTitle: sc.course.title,
credits: sc.course.credits,
type: sc.course.programmeCourses[0]?.type?.type || 'Unknown',
selected: true,
completed: false
}));

// Fetch elective requirements for the student's programme
const electiveRequirements = await ElectiveRequirement.findAll({
where: { programmeId: student.programmeId },
include: [{
model: Type,
attributes: ['type']
}],
attributes: ['amount']
});

// Create a map of elective requirements
const electiveRequirementsMap = electiveRequirements.reduce((acc, req) => {
acc[req.type.type] = req.amount;
return acc;
}, {});

// Combine completed and selected courses
const allCourses = [...completedCourseData, ...selectedCourseData];

// Group courses by type (category)
const coursesByType = allCourses.reduce((acc, course) => {
if (!acc[course.type]) {
acc[course.type] = [];
}
const stat = plan.get('planStatus');
const planId = plan.get('id');
const courses = await SelectedCourse.findAll({
attributes :['courseCode'],
where : {
AdvisingSessionId: planId
}
}).then(courses => courses.map(course => {
return course.get('courseCode');
}));
return{
year:year,
status:stat,
courses:courses
acc[course.type].push(course);
return acc;
}, {});

// Calculate credits remaining for each category
const calculateCreditsRemaining = (courses, type) => {
const requiredCredits = electiveRequirementsMap[type] || 0;
const completedCredits = courses.filter(course => course.completed).reduce((sum, course) => sum + course.credits, 0);
return Math.max(requiredCredits - completedCredits, 0);
};


// Construct the plan array
const plan = Object.entries(coursesByType).map(([category, courses]) => ({
category,
creditsRemaining: calculateCreditsRemaining(courses, category),
totalCreditsForCategory: electiveRequirementsMap[category] || 0,
courses: courses.map(course => ({
courseCode: course.courseCode,
courseTitle: course.courseTitle,
type: course.type,
selected: course.selected,
completed: course.completed,
credits: course.credits
}))
}));

// Prepare the response object in the specified format
return {
[studentId]: {
lastUpdated: advisingSession.updatedAt.toISOString().split('T')[0], // Use the updatedAt from AdvisingSession
status: advisingSession.planStatus || "Pending", // Use the status from AdvisingSession if it exists, otherwise default to "Pending"
plan: plan,
limit: 15
}
});
return courseplan;
}catch(error){
const msg = `Error in getting student's ${studentId} simple courseplan for semesterId ${semesterId}:`;
console.log(msg,error.message);
return null;
};

} catch (error) {
console.error("Error fetching student course plan:", error.message);
throw new Error(error.message || "Internal server error");
}
}
module.exports = { getStudentCoursePlan, getStudentCoursePlanSimple }
module.exports = { getStudentCoursePlan, getStudentCoursePlanByStudentIdAndSemesterId }
70 changes: 38 additions & 32 deletions controllers/getStudentCourses.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,54 @@
const StudentCourses = require("../models/StudentCourse");
const Semester = require("../models/Semester");
const Course = require("../models/Course");
const Student = require("../models/Student");

async function getStudentsCourses(studentId) {
try {
const studentObject = await Student.findByPk(studentId);
const studentFullName = `${studentObject.firstName} ${studentObject.lastName}`;
const studentCourses = await StudentCourses.findAll({
where: {
studentId: studentId
}
});

const processedCourses = await Promise.all(studentCourses.map(async (info) => {
const stdCourseInfo = info.dataValues;

const [semInfo, courseInfo] = await Promise.all([
Semester.findOne({
where: { studentId },
include: [
{
model: Semester,
attributes: ['academicYear', 'num'],
where: {
id: stdCourseInfo.semesterId
}
}),
Course.findOne({
as: 'semester'
},
{
model: Course,
attributes: ['title', 'credits'],
where: {
code: stdCourseInfo.courseCode
}
})
]);
as: 'course'
}
],
attributes: ['id', 'courseCode', 'grade', 'semesterId']
});
console.log(studentCourses);
// Process the data in one step without the need for nested promises
const processedCourses = studentCourses.map(course => {
const {
id,
courseCode,
grade,
semester: { num: semester, academicYear },
course: { title: courseName, credits: creditHours }
} = course.dataValues;

return {
id: stdCourseInfo.id,
courseCode: stdCourseInfo.courseCode,
courseName: courseInfo.title,
creditHours: courseInfo.credits,
grade: stdCourseInfo.grade,
semester: semInfo.num,
academicYear: semInfo.academicYear
id,
courseCode,
courseName,
creditHours,
grade,
semester,
academicYear
};
}));

return processedCourses;
});
return { fullName: studentFullName, processedCourses };
} catch (error) {
console.error("Error in getStudentsCourses:", error);
throw error;
console.error("Error fetching student courses:", error);
throw new Error('Failed to retrieve student courses'); // Adding more specific error handling
}
}

Expand Down
2 changes: 1 addition & 1 deletion db.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function createSequelizeInstance() {
if (env === 'production') {
// Extracting database connection information from the URL
const regex = /^postgres:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/(.+)$/;
const matches = process.env.POSTGRES_URL.match(regex);
const matches = RegExp(regex).exec(process.env.POSTGRES_URL);
if (!matches) {
throw new Error('Invalid POSTGRES_URL format');
}
Expand Down
Loading

0 comments on commit 033756f

Please sign in to comment.