Skip to content

Let a course nobody is assigned to be graded - #1961

Merged
vikrantwiz02 merged 1 commit into
FusionIIIT:prod/acad-reactfrom
vikrantwiz02:acad-project-course-roster
Aug 20, 2026
Merged

Let a course nobody is assigned to be graded#1961
vikrantwiz02 merged 1 commit into
FusionIIIT:prod/acad-reactfrom
vikrantwiz02:acad-project-course-roster

Conversation

@vikrantwiz02

Copy link
Copy Markdown
Member

Symptom

Uploading a grade sheet for PR3003 — Optional Project answers:

No students are registered in the selected section for this course.

while the very same screen lists the student as Registered — because that preview table is built client-side from the CSV, so it shows a roster the server has already rejected.

Cause

The course has no offering at all, and every one of its registrations therefore carries none:

reg: PR3003  sem=6  Regular  session='2025-26'  Even Semester
     course_instructor=None  section=None
offerings for PR3003: 0
registrations of PR3003: 86 | without an offering: 86

The roster in UploadGradesProfAPI narrows by section like this:

my_sections = {o.section_label for o in my_offerings}   # empty: no offerings exist
if programme_type == "UG" and None not in my_sections:
    regs = regs.filter(
        Q(course_instructor_id__in=my_offering_ids)                                     # empty
        | (Q(course_instructor__isnull=True) & Q(student_id__section__in=my_sections))   # empty
    )

Its own comment says a no-section (elective) offering owns all registrants — the None in my_sections case. But an empty set also satisfies None not in my_sections, so for a course with no offering the filter runs with two empty sets, matches nothing, and reports the roster as empty.

Fix

Require that a section actually exists before narrowing:

if programme_type == "UG" and my_sections and None not in my_sections:

A course with no offering now behaves like a no-section elective and owns all of its registrants. Sectioned courses are untouched, their set of sections being non-empty.

Verified through the real endpoint with the actual grade sheet: POST /examination/api/upload_grades_prof/ for PR3003, 2025-26 Even, returns 200 where it returned 400. The grade row that test wrote was removed afterwards; PR3003 is back to its 57 historical rows with none for 2025-26.

manage.py check clean, no migrations.

Worth a separate look

This is also a data condition: 86 students are registered in a course with no instructor assigned, so nothing in Course Instructors records who owns it. Grading works now regardless, but on the faculty side a professor with no offering still gets "Access denied: you are not assigned to teach this course this term" — correct by the letter, confusing for whoever actually supervises those projects.

A project course can have no offering at all: PR3003 Optional Project has no
CourseInstructor row, and all 86 of its registrations therefore carry no
offering. Uploading grades for it answered "No students are registered in the
selected section for this course" even though the student was plainly
registered, because the roster narrowed itself against an empty set of
sections -- `None not in my_sections` is true of an empty set as well as of a
set of named sections, so both halves of the section filter matched nothing.

The narrowing now requires a section to exist, which is what the surrounding
comment always intended: a course with no offering behaves like a no-section
elective and owns all of its registrants. Sectioned courses keep their present
behaviour, since their set of sections is not empty.

Uploading the real grade sheet for PR3003 answers 200 where it answered 400.
@vikrantwiz02
vikrantwiz02 merged commit 8b2f6d2 into FusionIIIT:prod/acad-react Aug 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant