CoolFace
Apppublic

vinodh0512/E-learning

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
server.js485 linesDownload Raw Back to root
1const express = require("express");2const cors = require("cors");3const { connectDB, getDB } = require("./db");4const { ObjectId } = require("mongodb");5const bcrypt = require("bcrypt");6 7const app = express();8app.use(cors());9app.use(express.json());10 11app.use((req, res, next) => {12  console.log(`[BACKEND LOG] ${req.method} ${req.url}`);13  next();14});15 16connectDB();17 18// DEBUG ROUTE19app.get('/test-erase', (req, res) => res.json({ message: "Erase route is reachable" }));20 21// -- DATA MANAGEMENT --22app.post('/admin/erase-database', async (req, res) => {23  console.log("CRITICAL: Erase database request received.");24  try {25    const db = getDB();26    const collections = ['students', 'instructors', 'courses', 'assignments', 'submissions', 'content', 'notes', 'notifications', 'enrollments'];27    for (const coll of collections) {28      await db.collection(coll).deleteMany({});29    }30    res.json({ message: "Institutional database reset successful." });31  } catch (error) {32    console.error("Erase error:", error);33    res.status(500).json({ error: error.message });34  }35});36 37app.get("/", (req, res) => {38  res.send("Backend is running ๐Ÿš€");39});40 41// -- DASHBOARD STATS --42app.get('/admin/stats', async (req, res) => {43  try {44    const db = getDB();45    const totalStudents = await db.collection('students').countDocuments();46    const totalTeachers = await db.collection('instructors').countDocuments();47    const activeCourses = await db.collection('courses').countDocuments(); // Total courses for now48    49    // For "Pending Approvals", we can count unevaluated submissions or courses with "Pending" status50    const pendingSubmissions = await db.collection('submissions').countDocuments({ evaluated: false });51    const pendingCourses = await db.collection('courses').countDocuments({ status: 'Pending' });52    const pendingApprovals = pendingSubmissions + pendingCourses;53 54    // Presence logic (mocking based on totals since no attendance system exists yet)55    // In a real system, this would query an attendance collection56    const studentsPresent = totalStudents > 0 ? Math.floor(totalStudents * 0.94) : 0;57    const facultyPresent = totalTeachers > 0 ? Math.floor(totalTeachers * 0.97) : 0;58 59    res.json({60      totalStudents: totalStudents,61      totalTeachers: totalTeachers,62      studentsPresent: studentsPresent,63      facultyPresent: facultyPresent,64      activeCourses: activeCourses,65      pendingApprovals: pendingApprovals66    });67  } catch (error) {68    res.status(500).json({ error: error.message });69  }70});71 72// -- AUTH & USERS --73app.post('/auth/login', async (req, res) => {74  try {75    const { role, identifier, password } = req.body;76    if (!['student', 'instructor', 'admin'].includes(role)) return res.status(400).json({ error: 'Invalid role' });77    78    const db = getDB();79    const collectionName = role + 's';80    81    const user = await db.collection(collectionName).findOne({82      $or: [{ email: identifier }, { username: identifier }]83    });84 85    if (user) {86        let isMatch = false;87        if (user.password && !user.password.startsWith('$2b$')) {88            isMatch = (user.password === password);89            if(isMatch) {90                const hashedPassword = await bcrypt.hash(password, 10);91                await db.collection(collectionName).updateOne(92                    { _id: user._id },93                    { $set: { password: hashedPassword } }94                );95            }96        } else {97            isMatch = await bcrypt.compare(password, user.password);98        }99 100        if (isMatch) {101            res.json({ 102                user: { 103                    _id: user._id, 104                    username: user.username, 105                    email: user.email, 106                    role,107                    dept: user.dept || '',108                    year: user.year || '',109                    section: user.section || '',110                    rollno: user.rollno || '',111                    batch: user.batch || ''112                } 113            });114        } else {115            res.status(401).json({ error: 'Invalid credentials' });116        }117    } else {118      res.status(401).json({ error: 'Invalid credentials' });119    }120  } catch (error) {121    res.status(500).json({ error: error.message });122  }123});124 125app.post('/admin/create-user', async (req, res) => {126  try {127    const { role, password, ...otherData } = req.body;128    if (!['student', 'instructor'].includes(role)) return res.status(400).json({ error: 'Invalid role' });129    const db = getDB();130    const hashedPassword = await bcrypt.hash(password, 10);131    const result = await db.collection(role + 's').insertOne({ 132      ...otherData, 133      password: hashedPassword 134    });135    res.json({ message: "User created", result });136  } catch (error) {137    res.status(500).json({ error: error.message });138  }139});140 141app.put('/users/:role/:id', async (req, res) => {142  try {143    const { role, id } = req.params;144    const { password, ...updateData } = req.body;145    if (!['student', 'instructor', 'admin'].includes(role)) return res.status(400).json({ error: 'Invalid role' });146    147    const db = getDB();148    if (password) {149        updateData.password = await bcrypt.hash(password, 10);150    }151 152    let query;153    try {154        query = { _id: new ObjectId(id) };155    } catch(e) {156        query = { _id: id }; // Fallback for string-based IDs157    }158 159    const result = await db.collection(role + 's').updateOne(160      query,161      { $set: updateData }162    );163    res.json(result);164  } catch (error) {165    res.status(500).json({ error: error.message });166  }167});168 169app.get('/student', async (req, res) => {170  const db = getDB();171  const students = await db.collection("students").find({}).project({ password: 0 }).toArray();172  res.json(students);173});174 175app.get('/instructor', async (req, res) => {176  const db = getDB();177  const instructors = await db.collection("instructors").find({}).project({ password: 0 }).toArray();178  res.json(instructors);179});180 181app.get('/users/:role/:id', async (req, res) => {182  try {183    const { role, id } = req.params;184    const db = getDB();185    186    let query;187    try {188        query = { _id: new ObjectId(id) };189    } catch(e) {190        query = { _id: id }; // Fallback for string-based IDs191    }192 193    const user = await db.collection(role + 's').findOne(query, { projection: { password: 0 } });194    res.json(user);195  } catch (error) {196    res.status(500).json({ error: error.message });197  }198});199 200app.delete('/users/:role/:id', async (req, res) => {201  try {202    const { role, id } = req.params;203    const db = getDB();204    const result = await db.collection(role + 's').deleteOne({ _id: new ObjectId(id) });205    res.json(result);206  } catch (error) {207    res.status(500).json({ error: error.message });208  }209});210 211// -- COURSES --212app.post('/courses', async (req, res) => {213  try {214    const db = getDB();215    const result = await db.collection('courses').insertOne(req.body);216    res.json(result);217  } catch (error) {218    res.status(500).json({ error: error.message });219  }220});221 222app.get('/courses', async (req, res) => {223  try {224    const db = getDB();225    const courses = await db.collection('courses').find({}).toArray();226    res.json(courses);227  } catch (error) {228    res.status(500).json({ error: error.message });229  }230});231 232app.put('/courses/:id', async (req, res) => {233  try {234    const { id } = req.params;235    const db = getDB();236    237    let query;238    try {239        query = { _id: new ObjectId(id) };240    } catch(e) {241        query = { _id: id }; // Fallback for string-based IDs242    }243 244    const result = await db.collection('courses').updateOne(245      query,246      { $set: req.body }247    );248    console.log(`[BACKEND] Course Update Outcome for ${id}: Matched=${result.matchedCount}, Modified=${result.modifiedCount}`);249    res.json(result);250  } catch (error) {251    res.status(500).json({ error: error.message });252  }253});254 255app.delete('/courses/:id', async (req, res) => {256  try {257    const { id } = req.params;258    const db = getDB();259    const result = await db.collection('courses').deleteOne({ _id: new ObjectId(id) });260    res.json(result);261  } catch(error) {262    res.status(500).json({ error: error.message });263  }264});265 266// -- ASSIGNMENTS --267app.post('/assignments', async (req, res) => {268  try {269    const db = getDB();270    const result = await db.collection('assignments').insertOne(req.body);271    res.json(result);272  } catch (error) {273    res.status(500).json({ error: error.message });274  }275});276 277app.get('/assignments', async (req, res) => {278  try {279    const db = getDB();280    const assignments = await db.collection('assignments').find({}).toArray();281    res.json(assignments);282  } catch (error) {283    res.status(500).json({ error: error.message });284  }285});286 287app.delete('/assignments/:id', async (req, res) => {288  try {289    const { id } = req.params;290    const db = getDB();291    const result = await db.collection('assignments').deleteOne({ _id: new ObjectId(id) });292    res.json(result);293  } catch (error) {294    res.status(500).json({ error: error.message });295  }296});297 298// -- SUBMISSIONS --299app.post('/submissions', async (req, res) => {300  try {301    const db = getDB();302    const submission = {303      ...req.body,304      createdAt: new Date(),305      evaluated: false,306      grade: '',307      feedback: ''308    };309    const result = await db.collection('submissions').insertOne(submission);310    311    await db.collection('assignments').updateOne(312      { _id: new ObjectId(req.body.assignmentId) },313      { $inc: { submissionsCount: 1 } }314    );315    316    res.json(result);317  } catch (error) {318    res.status(500).json({ error: error.message });319  }320});321 322app.get('/submissions/:assignmentId', async (req, res) => {323  try {324    const { assignmentId } = req.params;325    const db = getDB();326    const submissions = await db.collection('submissions').find({ assignmentId }).toArray();327    res.json(submissions);328  } catch (error) {329    res.status(500).json({ error: error.message });330  }331});332 333app.put('/submissions/:id', async (req, res) => {334  try {335    const { id } = req.params;336    const { grade, feedback } = req.body;337    const db = getDB();338    const result = await db.collection('submissions').updateOne(339      { _id: new ObjectId(id) },340      { $set: { grade, feedback, evaluated: true } }341    );342    res.json(result);343  } catch (error) {344    res.status(500).json({ error: error.message });345  }346});347 348// -- CONTENT --349app.post('/content', async (req, res) => {350  try {351    const db = getDB();352    const result = await db.collection('content').insertOne(req.body);353    res.json(result);354  } catch (error) {355    res.status(500).json({ error: error.message });356  }357});358 359app.get('/content', async (req, res) => {360  try {361    const db = getDB();362    const content = await db.collection('content').find({}).toArray();363    res.json(content);364  } catch (error) {365    res.status(500).json({ error: error.message });366  }367});368 369app.put('/content/:id', async (req, res) => {370  try {371    const { id } = req.params;372    const { items } = req.body;373    const db = getDB();374    const result = await db.collection('content').updateOne(375      { _id: new ObjectId(id) },376      { $set: { items } }377    );378    res.json(result);379  } catch (error) {380    res.status(500).json({ error: error.message });381  }382});383 384// -- NOTES --385app.post('/notes', async (req, res) => {386  try {387    const db = getDB();388    const result = await db.collection('notes').insertOne(req.body);389    res.json(result);390  } catch (error) {391    res.status(500).json({ error: error.message });392  }393});394 395app.get('/notes', async (req, res) => {396  try {397    const db = getDB();398    const notes = await db.collection('notes').find({}).toArray();399    res.json(notes);400  } catch (error) {401    res.status(500).json({ error: error.message });402  }403});404 405app.put('/notes/:id/upvote', async (req, res) => {406  try {407    const { id } = req.params;408    const db = getDB();409    const result = await db.collection('notes').updateOne(410      { _id: new ObjectId(id) },411      { $inc: { upvotes: 1 } }412    );413    res.json(result);414  } catch (error) {415    res.status(500).json({ error: error.message });416  }417});418 419// -- NOTIFICATIONS --420app.post('/notifications', async (req, res) => {421  try {422    const db = getDB();423    const notification = {424      ...req.body,425      createdAt: new Date()426    };427    const result = await db.collection('notifications').insertOne(notification);428    res.json(result);429  } catch (error) {430    res.status(500).json({ error: error.message });431  }432});433 434app.get('/notifications', async (req, res) => {435  try {436    const db = getDB();437    const notifications = await db.collection('notifications').find({}).sort({ createdAt: -1 }).toArray();438    res.json(notifications);439  } catch (error) {440    res.status(500).json({ error: error.message });441  }442});443 444// -- ENROLLMENTS --445app.post('/enroll', async (req, res) => {446  try {447    const { studentId, courseId } = req.body;448    console.log(`Enrollment Request: Student=${studentId}, Course=${courseId}`);449    const db = getDB();450    const existing = await db.collection('enrollments').findOne({ studentId, courseId });451    if (existing) {452      console.log("Already enrolled.");453      return res.status(400).json({ error: 'Already enrolled' });454    }455    const result = await db.collection('enrollments').insertOne({ studentId, courseId, status: 'Active' });456    console.log("Enrollment successful.");457    res.json(result);458  } catch (error) { 459    console.error("Enrollment error:", error);460    res.status(500).json({ error: error.message }); 461  }462});463 464app.get('/enroll/:studentId', async (req, res) => {465  try {466    const { studentId } = req.params;467    const db = getDB();468    const enrollments = await db.collection('enrollments').find({ studentId }).toArray();469    res.json(enrollments);470  } catch (error) { res.status(500).json({ error: error.message }); }471});472 473const path = require('path');474app.use(express.static(path.join(__dirname, 'public')));475 476// Catch-all middleware to serve the frontend index.html477app.use((req, res) => {478  res.sendFile(path.join(__dirname, 'public', 'index.html'));479});480 481const PORT = process.env.PORT || 5000;482app.listen(PORT, "0.0.0.0", () => {483  console.log(`Server running on port ${PORT}`);484});485