Skip to content

[Bug]: Admin delete orphans enrolments, payments, reviews and bookmarks, and never removes the uploaded videos #74

Description

@MOHITKOURAV01

Summary

deleteUserController and deleteCourseController in backend/controllers/adminController.js are both a single findByIdAndDelete with nothing after it. Everything that references the deleted row stays in the database, and every uploaded video that belonged to a deleted course stays on disk forever.

const user = await userSchema.findByIdAndDelete(userid);   // enrolments, payments, reviews, bookmarks, logs all survive
const course = await courseSchema.findByIdAndDelete(courseid); // plus every section .mp4 in backend/uploads

The teacher-facing path already does this properly. courseDeletionController.js calls removeCourseVideoFiles(deletedCourse) and is already written to accept an admin (["teacher", "admin"].includes(role)), but adminRoutes.js wires DELETE /api/admin/deletecourse/:courseid to the weaker duplicate in adminController.js instead. So the same action cleans up or does not depending on which screen it was triggered from.

Expected result

Deleting a user removes, in one operation:

  • their enrolments (enrolledCourses)
  • their payment records (coursePayments)
  • their reviews (courseReviews) and the affected courses' rating summaries
  • their bookmarks (courseBookmarks)
  • courses they authored, if they were a teacher, including those courses' videos

Deleting a course removes its enrolments, payments, reviews and bookmarks, and deletes its section videos from backend/uploads, exactly like the teacher route does.

The response should report what was removed so the admin dashboard can show it.

Actual result

  • GET /api/admin/enrolled-courses populates userId/courseId on rows whose referenced document is gone, so the dashboard renders rows with a blank student and a blank course.
  • GET /api/admin/payments does the same, and the payment history of deleted users is still fully readable.
  • courseReviews keeps rows for deleted courses, and getSummary() keeps counting them, so a course's average rating is computed from reviews by accounts that no longer exist.
  • backend/uploads grows without limit. There are already orphaned .mp4 files checked into the repo.
  • getEnrolledCoursesController has to defensively skip enrolments whose course is missing (added in [Bug]: getallcoursesuser runs N+1 queries and returns null rows that crash the enrolled-courses page #65) purely because deletion does not clean up.

Steps to reproduce

  1. Sign in as admin, create a teacher, have them publish a course with a video section, and enrol a student in it.
  2. DELETE /api/admin/deletecourse/:courseid.
  3. ls backend/uploads — the section video is still there.
  4. db.enrolledcourses.find({ courseId: <id> }) — the enrolment is still there.
  5. db.coursereviews.find({ courseId: <id> }) — the reviews are still there.
  6. Open the admin "Enrolled courses" tab — a row renders with an empty course title.
  7. Repeat with DELETE /api/admin/deleteuser/:userid; the payments and enrolments for that user survive.

Notes

  • The two admin controllers should not stay as a second implementation of deletion. Routing /api/admin/deletecourse at courseDeletionController gets the file cleanup for free, and the cascade itself belongs in a shared utility that both entry points call.
  • courseModel.userId is a String while enrolledCourseModel.userId is an ObjectId, so a cascade has to query authored courses by string and enrolments by ObjectId. Worth handling explicitly rather than assuming one shape.
  • A deleted enrolment should also decrement course.enrolled, otherwise the learner count on the catalogue card drifts upward permanently.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

ECSoC26Required label for a PR to be eligible for Sentinel scoring

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions