From 9c83a865764b42eb1e0067305e07522d6590bb79 Mon Sep 17 00:00:00 2001 From: Moaid Hashem Date: Tue, 8 Oct 2024 22:38:58 +0300 Subject: [PATCH 1/6] correcting user and courses realtion --- controllers/handelCourse.js | 27 +++++++++++++++------ controllers/handelUser.js | 48 ++++++++++++++++++++++++++++--------- models/courseModel.js | 6 ++--- models/usersModel.js | 4 ++-- routes/userRoute.js | 3 ++- 5 files changed, 64 insertions(+), 24 deletions(-) diff --git a/controllers/handelCourse.js b/controllers/handelCourse.js index 246c66e..b8be872 100644 --- a/controllers/handelCourse.js +++ b/controllers/handelCourse.js @@ -42,29 +42,42 @@ const getCourseById = async (req, res) => { const createCourse = async (req, res) => { const course = req.body; try { - if(req.file){ - course.image=req.file.path; + if (req.file) { + course.image = req.file.path; } + const newCourse = new Course(course); const savedCourse = await newCourse.save(); + await User.findByIdAndUpdate( + course.professor, + { $push: { createdCourses: savedCourse._id} }, + { new: true } + ); + res.status(201).json({ message: "Course created successfully", data: savedCourse }); } catch (err) { + console.error("Error creating course:", err); res.status(400).json({ message: err.message }); } }; const updateCourse = async (req, res) => { const { id } = req.params; - const updates = req.body; + const { quizId } = req.body; + console.log(id, quizId) try { - const updatedCourse = await Course.findByIdAndUpdate(id, updates, { - new: true, - }); + const updatedCourse = await Course.findByIdAndUpdate( + id, + { $push: { quizzes: quizId } }, // Adds the quizId to the quizzes array + { new: true } // Return the updated document + ); + if (!updatedCourse) { return res.status(404).json({ message: "Course not found" }); } - res.status(200).json({ message: "Course updated successfully" }); + + res.status(200).json({ message: "Course updated successfully", updatedCourse }); } catch (err) { res.status(400).json({ message: err.message }); } diff --git a/controllers/handelUser.js b/controllers/handelUser.js index 2b4b602..f026c28 100644 --- a/controllers/handelUser.js +++ b/controllers/handelUser.js @@ -85,7 +85,22 @@ const deleteall = async (req, res) => { } } -const login = async (req, res) => { +const getAllProfessors = async (req,res) => { + try { + const professors = await usermodel.find({ role: "professor" }).select("name email createdCourses"); + if (professors) { + res.status(200).json({ message: "all professors", data: professors }); + + } else { + res.status(404).json({ message: 'can not be fouund' }) + } + + } catch (e) { + res.json({ message: e.message }) + } + }; + + const login = async (req, res) => { const { email, password } = req.body; if (!email || !password) { @@ -93,7 +108,8 @@ const login = async (req, res) => { } try { - const user = await usermodel.findOne({ email }); + const user = await usermodel.findOne({ email }).populate('createdCourses', 'title'); + if (!user) { return res.status(401).json({ message: "Invalid email or password" }); } @@ -103,12 +119,19 @@ const login = async (req, res) => { return res.status(401).json({ message: "Invalid email or password" }); } - // Sign token with user data const token = jwt.sign( - { data: {name:user.name, email: user.email, id: user._id, role: user.role, image: user.image, - enrolledCourses: user.enrolledCourses, - createdCourses: user.createdCourses, - quizzes: user.quizzes } }, + { + data: { + name: user.name, + email: user.email, + id: user._id, + role: user.role, + image: user.image, + enrolledCourses: user.enrolledCourses, + createdCourses: user.createdCourses, + quizzes: user.quizzes + } + }, process.env.secret, { expiresIn: "3h" } ); @@ -117,14 +140,16 @@ const login = async (req, res) => { return res.status(200).json({ message: "success", token, - user: { id: user._id, + user: { + id: user._id, name: user.name, email: user.email, role: user.role, image: user.image, - enrolledCourses: user.enrolledCourses, + enrolledCourses: user.enrolledCourses, createdCourses: user.createdCourses, - quizzes: user.quizzes } + quizzes: user.quizzes + } }); } catch (error) { return res.status(500).json({ message: "Server error, please try again later" }); @@ -132,6 +157,7 @@ const login = async (req, res) => { }; + const uploadImage = async (req, res) => { try { @@ -147,4 +173,4 @@ const uploadImage = async (req, res) => { res.status(500).send(err.message); } }; -module.exports = { getall, getByid, updateOne,createone,deleteOne,deleteall,login, uploadImage } +module.exports = { getall, getByid, updateOne,createone,deleteOne,deleteall,login, uploadImage,getAllProfessors } diff --git a/models/courseModel.js b/models/courseModel.js index 78239c9..c320d81 100644 --- a/models/courseModel.js +++ b/models/courseModel.js @@ -14,9 +14,9 @@ const courseSchema = new mongoose.Schema({ trim: true, }, professor: { - type: String, + type: mongoose.Schema.Types.ObjectId, + ref: "User", required: true, - trim: true, }, major: { type: String, @@ -56,4 +56,4 @@ const courseSchema = new mongoose.Schema({ }); const Course = mongoose.model("Course", courseSchema); -module.exports = Course; +module.exports = Course; \ No newline at end of file diff --git a/models/usersModel.js b/models/usersModel.js index d173a0b..16f8a92 100644 --- a/models/usersModel.js +++ b/models/usersModel.js @@ -35,8 +35,8 @@ const userSchema = new mongoose.Schema({ enrolledCourses: [{ type: mongoose.Schema.Types.ObjectId, ref: "Course" }], // For Instructors, store references to created courses and quizzes - createdCourses: [{ type: mongoose.Schema.Types.ObjectId, ref: "Course" }], - + createdCourses: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Course' }], + quizzes: [ { quizId: { type: mongoose.Schema.Types.ObjectId, ref: "Quiz" }, diff --git a/routes/userRoute.js b/routes/userRoute.js index f3d116e..37980f4 100644 --- a/routes/userRoute.js +++ b/routes/userRoute.js @@ -1,6 +1,6 @@ const upload = require('../Middlewares/uploadConfig'); -const { getall, getByid, updateOne,createone,deleteOne,deleteall,login,uploadImage} = module.require("../controllers/handelUser"); +const { getall, getByid, updateOne,createone,deleteOne,deleteall,login,uploadImage, getAllProfessors} = module.require("../controllers/handelUser"); const express = module.require('express') const router=express.Router(); @@ -8,6 +8,7 @@ const app = express(); const {auth,restrict}=module.require('../Middlewares/auth') app.use(express.json()) router.get('/',auth,restrict("admin"),getall) +router.get('/professor', getAllProfessors); router.post('/register', upload.single('image'), createone); router.get('/:id',getByid) router.patch('/:id',updateOne) From 41ab9ee005aaeb855d737cf7d2a434a51d4e9c96 Mon Sep 17 00:00:00 2001 From: Moaid Hashem Date: Fri, 11 Oct 2024 06:29:56 +0300 Subject: [PATCH 2/6] -adding get students -correcting update one for user --- controllers/handelCourse.js | 48 ++++++++++++++++++++++++ controllers/handelUser.js | 73 +++++++++++++++++++++++++------------ routes/courseRoute.js | 3 +- routes/userRoute.js | 2 +- 4 files changed, 100 insertions(+), 26 deletions(-) diff --git a/controllers/handelCourse.js b/controllers/handelCourse.js index b8be872..0493f0b 100644 --- a/controllers/handelCourse.js +++ b/controllers/handelCourse.js @@ -1,5 +1,6 @@ const Course = require("../models/courseModel"); const User = require("../models/usersModel"); +const Quiz = require("../models/quizModel") const getAllCourse = async (req, res) => { try { @@ -181,6 +182,52 @@ const enrollInCourse = async (req, res)=>{ return res.status(500).json({ message: error.message }); } } +const getStudentsInCourse = async (req, res) => { + try { + const { courseId } = req.params; + + // Fetch the course to get the enrolled students + const course = await Course.findById(courseId).populate('students'); + + if (!course) { + return res.status(404).json({ message: "Course not found" }); + } + + // Find all students enrolled in the course + const enrolledStudents = await User.find( + { _id: { $in: course.students } }, + "name email quizzes" + ); + + // Find all quizzes in the course + const quizzes = await Quiz.find({ course: courseId }); + + // Fetch quiz scores for each student + const studentsData = await Promise.all( + enrolledStudents.map(async (student) => { + let totalScore = 0; + + // Iterate through the student's quizzes and sum the total score + student.quizzes.forEach(quiz => { + totalScore += quiz.totalScore; + }); + + return { + name: student.name, + email: student.email, + totalScore: totalScore, // Combined total score of all quizzes + }; + }) + ); + + res.status(200).json({ + message: "Students data retrieved successfully", + data: studentsData, + }); + } catch (error) { + res.status(500).json({ message: "Server error", error: error.message }); + } +}; module.exports = { @@ -193,4 +240,5 @@ module.exports = { deleteCourseById, deleteAllCourse, enrollInCourse, + getStudentsInCourse }; diff --git a/controllers/handelUser.js b/controllers/handelUser.js index f026c28..3faedf2 100644 --- a/controllers/handelUser.js +++ b/controllers/handelUser.js @@ -34,35 +34,59 @@ const getByid = async (req, res) => { } const updateOne = async (req, res) => { try { - let { id } = req.params; - let {password,...newupdate} = req.body; - const updatedata={...newupdate} - if(password){ - const hashedPassword = await bcrypt.hash(password, 10); // Hash the new password - updatedata.password = hashedPassword; - } - let updatedtuser = await usermodel.findByIdAndUpdate(id, updatedata , { new: true }); - res.json({ message: "updated", data: updatedtuser }) - - } catch (e) { - res.json({ message: "not updated", error: e.message }) - } -} -const createone = async (req, res) => { - try { - let newuser = req.body; + const { id } = req.params; + const { password, ...newUpdate } = req.body; // Extract other fields from req.body + const updateData = { ...newUpdate }; + + // Handle password hashing if provided + if (password) { + const hashedPassword = await bcrypt.hash(password, 10); + updateData.password = hashedPassword; + } + // If an image is provided, handle file upload if (req.file) { - newuser.image = req.file.path; + updateData.image = req.file.path; // Set image path from multer file upload } - let inserteduser = await usermodel.create(newuser); - res.json({ message: "created", data: inserteduser }); - } catch (err) { - res.json({ message: "cannot be created", error: err.message }); + // Find the user and update + const updatedUser = await usermodel.findByIdAndUpdate(id, updateData, { new: true }); + + if (!updatedUser) { + return res.status(404).json({ message: "User not found" }); + } + + res.status(200).json({ message: "Profile updated", data: updatedUser }); + } catch (error) { + res.status(500).json({ message: "Error updating profile", error: error.message }); } }; + +const createone = async (req, res) => { + try { + // Extract user data from the request body + let newuser = { + name: req.body.name, + email: req.body.email, + password: req.body.password, + }; + + // Check if a file was uploaded and set the image path if it exists + if (req.file) { + newuser.image = req.file.path; + } + + // Insert the new user into the database + let inserteduser = await usermodel.create(newuser); + res.json({ message: "User created successfully", data: inserteduser }); + } catch (err) { + console.error(err); // Log the error for debugging + res.status(400).json({ message: "User cannot be created", error: err.message }); + } +}; + + const deleteOne =async (req, res) => { try { let { id } = req.params; @@ -118,6 +142,7 @@ const getAllProfessors = async (req,res) => { if (!isValid) { return res.status(401).json({ message: "Invalid email or password" }); } + const imageUrl = `${req.protocol}://${req.get('host')}/${user.image}`; const token = jwt.sign( { @@ -126,7 +151,7 @@ const getAllProfessors = async (req,res) => { email: user.email, id: user._id, role: user.role, - image: user.image, + image: imageUrl, enrolledCourses: user.enrolledCourses, createdCourses: user.createdCourses, quizzes: user.quizzes @@ -145,7 +170,7 @@ const getAllProfessors = async (req,res) => { name: user.name, email: user.email, role: user.role, - image: user.image, + image: imageUrl, enrolledCourses: user.enrolledCourses, createdCourses: user.createdCourses, quizzes: user.quizzes diff --git a/routes/courseRoute.js b/routes/courseRoute.js index dec6375..2fe68f8 100644 --- a/routes/courseRoute.js +++ b/routes/courseRoute.js @@ -12,6 +12,7 @@ const { deleteCourseById, deleteAllCourse, enrollInCourse, + getStudentsInCourse } = require("../controllers/handelCourse"); app.use(express.json()); @@ -24,7 +25,7 @@ router.post('/uploadCourseImage/:id',upload.single('image'),uploadImage); router.post('/uploadCourseContent/:id',upload.single('pdfFile'),uploadContent); router.delete("/:id", deleteCourseById); router.delete("/", deleteAllCourse); - +router.get("/:courseId/students", getStudentsInCourse); module.exports = router; diff --git a/routes/userRoute.js b/routes/userRoute.js index 37980f4..f09f23f 100644 --- a/routes/userRoute.js +++ b/routes/userRoute.js @@ -11,7 +11,7 @@ router.get('/',auth,restrict("admin"),getall) router.get('/professor', getAllProfessors); router.post('/register', upload.single('image'), createone); router.get('/:id',getByid) -router.patch('/:id',updateOne) +router.patch('/:id', upload.single('image'), updateOne); router.delete('/:id',deleteOne) router.delete('/',auth,restrict("admin"),deleteall) router.post('/login',login) From 8b077ef7ffb020846fa7810d7d7e8ef400f44763 Mon Sep 17 00:00:00 2001 From: ahmedashrafdiv Date: Fri, 11 Oct 2024 06:44:58 +0300 Subject: [PATCH 3/6] edit_in_handleCourse --- controllers/handelCourse.js | 2 +- controllers/handelQuiz.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/handelCourse.js b/controllers/handelCourse.js index 0493f0b..9f8f31a 100644 --- a/controllers/handelCourse.js +++ b/controllers/handelCourse.js @@ -4,7 +4,7 @@ const Quiz = require("../models/quizModel") const getAllCourse = async (req, res) => { try { - const courses = await Course.find().populate("quizzes").populate("students"); + const courses = await Course.find().populate("quizzes").populate("students").populate("professor", "name"); if (courses.length == 0) { return res.status(404).json({ message: "No Courses Found!" }); } diff --git a/controllers/handelQuiz.js b/controllers/handelQuiz.js index 1f9f148..105e2a7 100644 --- a/controllers/handelQuiz.js +++ b/controllers/handelQuiz.js @@ -82,7 +82,7 @@ updateQuiz = async (req, res) => { retriveQuizs = async (req, res) => { try { - const retrivedQuizes = await Quiz.find(); + const retrivedQuizes = await Quiz.find().populate("quizzes","title"); if (!retrivedQuizes) return res.status(404).json({ message: "Quizes not found" }); res From 5df080d0be71dd337d46aa409033edba08426222 Mon Sep 17 00:00:00 2001 From: Moaid Hashem Date: Fri, 11 Oct 2024 09:06:59 +0300 Subject: [PATCH 4/6] -Editing update course to accept both quizzes and other updates --- controllers/handelCourse.js | 41 ++++++++++++++++++++++++------------- routes/courseRoute.js | 2 +- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/controllers/handelCourse.js b/controllers/handelCourse.js index 9f8f31a..83e5fc6 100644 --- a/controllers/handelCourse.js +++ b/controllers/handelCourse.js @@ -64,23 +64,36 @@ const createCourse = async (req, res) => { }; const updateCourse = async (req, res) => { - const { id } = req.params; - const { quizId } = req.body; - console.log(id, quizId) + const { title, major, professor, duration, quizId } = req.body; + const updates = {}; + if (title) updates.title = title; + if (major) updates.major = major; + if (professor) updates.professor = professor; + if (duration) updates.duration = duration; + try { - const updatedCourse = await Course.findByIdAndUpdate( - id, - { $push: { quizzes: quizId } }, // Adds the quizId to the quizzes array - { new: true } // Return the updated document - ); + const update = { + $set: updates, + }; - if (!updatedCourse) { - return res.status(404).json({ message: "Course not found" }); - } + if (quizId) { + update.$push = { quizzes: quizId }; + } - res.status(200).json({ message: "Course updated successfully", updatedCourse }); - } catch (err) { - res.status(400).json({ message: err.message }); + const updatedCourse = await Course.updateOne( + { _id: req.params.id }, + update, + { new: true } + ); + + if (updatedCourse.nModified === 0) { + return res.status(404).json({ message: 'Course not found or no changes made.' }); + } + + res.status(200).json({ message: 'Course updated successfully', updatedCourse }); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Internal server error' }); } }; diff --git a/routes/courseRoute.js b/routes/courseRoute.js index 2fe68f8..78b99b4 100644 --- a/routes/courseRoute.js +++ b/routes/courseRoute.js @@ -19,7 +19,7 @@ app.use(express.json()); router.get("/", getAllCourse); router.get("/:id", getCourseById); router.post("/", upload.single('image'),createCourse); -router.put("/:id", updateCourse); +router.patch("/:id", updateCourse); router.post("/enroll/:courseId/:studentId", enrollInCourse); router.post('/uploadCourseImage/:id',upload.single('image'),uploadImage); router.post('/uploadCourseContent/:id',upload.single('pdfFile'),uploadContent); From ef0ca6be64eec211167453430424e18de0f56ebd Mon Sep 17 00:00:00 2001 From: Moaid Hashem Date: Sat, 12 Oct 2024 03:19:08 +0300 Subject: [PATCH 5/6] -Deploying --- vercel.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 vercel.json diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..cb22f1a --- /dev/null +++ b/vercel.json @@ -0,0 +1,15 @@ +{ + "version": 2, + "builds": [ + { + "src": "index.js", + "use": "@vercel/node" + } + ], + "routes": [ + { + "src": "/(.*)", + "dest": "index.js" + } + ] + } \ No newline at end of file From cd1dc3cca1ed4580bd9bbb15f62e282f89c7cd69 Mon Sep 17 00:00:00 2001 From: Moaid Hashem Date: Sat, 12 Oct 2024 04:08:28 +0300 Subject: [PATCH 6/6] -fixing bugs --- controllers/handelUser.js | 1 + 1 file changed, 1 insertion(+) diff --git a/controllers/handelUser.js b/controllers/handelUser.js index 3faedf2..d0f7178 100644 --- a/controllers/handelUser.js +++ b/controllers/handelUser.js @@ -70,6 +70,7 @@ const createone = async (req, res) => { name: req.body.name, email: req.body.email, password: req.body.password, + role: req.body.role }; // Check if a file was uploaded and set the image path if it exists