Skip to content

Open the student-admission screens to the programme roles, and fix two announcement holes - #1958

Merged
vikrantwiz02 merged 1 commit into
FusionIIIT:prod/acad-reactfrom
vikrantwiz02:acad-roles-followups
Aug 18, 2026
Merged

vikrantwiz02 merged 1 commit into
FusionIIIT:prod/acad-reactfrom
vikrantwiz02:acad-roles-followups

Conversation

@vikrantwiz02

@vikrantwiz02 vikrantwiz02 commented Aug 18, 2026 •

Copy link
Copy Markdown
Member

Follow-up to #1957. Checking the three roles against a copy of production turned up three gaps that pass left behind.

A role-targeted announcement reached nobody

The recipient filter required every recipient to be a student of the sender's programme, so faculty failed it. An Acad UG announcement to Professor was created and notified 0 people where acadadmin notified 11 — the announcement row existed and nobody heard about it.

scope_recipients() now drops out-of-scope students and keeps anyone who is not a student, since faculty and staff are not programme-bound.

audience, as Acad UG before after acadadmin
programme UG 2971 2971 2971
programme PG 403 refused 403 refused 135
role Professor 0 11 11
everyone 2971 3232 3368

The 136 users dropped from "everyone" are exactly the 135 PG students plus one student with no batch.

The compose helpers were still acadadmin-only

announcement_audience_options and search_users both returned 403 to all three roles, so they could submit an announcement through the API but could not open the form that builds one. Both now accept them, and the recipient search is scoped before its [:20] slice — Acad UG searching 25MCSA gets 0 hits, Acad PG gets 20 — so a programme admin cannot pick a student whose notification would then be dropped on send.

The 26 student-admission views were closed, leaving a 403 behind a sidebar entry

adminUpcomingBatches is in the three roles' nav, but list_students and 25 sibling views in views_student_management.py were gated to acadadmin/Dean Academic. All 26 are now open and scoped:

  • lists, exports and upload history narrow to the role's own level
  • per-record reads and writes refuse a record from another level
  • create / upload / seat-configuration paths validate the programme they are asked to act on
  • consolidating duplicate curriculums or batches is confined to in-scope records, so a programme admin cannot merge another level's data away
  • the bulk status update names the ids it refuses rather than skipping them silently, and only judges ids from the UG/PG table — PhD records have their own id space, and the per-student call guards itself

The gate is ("acadadmin", "Dean Academic") + SCOPED_ACAD_ROLES, deliberately not ALL_ACAD_ROLES, which would also have admitted studentacadadmin — a role that never had access here.

Verified against production-shaped data

endpoint Acad UG Acad PG Acad Ph.D. acadadmin
list_students 611 144 0 755
upload_history 2 2 0 4
sync_batch_data 30 13 0 43
batches/curriculum_status 30 13 0 43
find_duplicate_curriculums 5 5 0 10
download_students/ug/ 150 KB 403 403 150 KB
download_students/pg/ 403 37 KB 403 37 KB

Every partition sums to the unscoped total. On the write side, against a real PG record: get_student / update_student_status / delete_student refuse Acad UG with 403 and succeed for Acad PG; add_single_student(pg), save_students_batch(pg), process_excel_upload(pg), create_batch(M.Tech) and set_total_seats(M.Tech) refuse Acad UG while Acad PG passes the gate and fails only on its own field validation; consolidation refuses Acad UG for both a PG curriculum and a PG batch; a bulk update over one PG and one UG id gives Acad UG "1 successful, 1 failed" against acadadmin's "2 successful, 0 failed". Every write ran inside a rolled-back transaction, so the database is untouched.

Two helpers were wrong rather than missing

scope_admission_records filtered on programme_type, a field only the UG/PG model has, so it would have raised FieldError on PhD records; it now falls back to "PhD by model". The programme-name table (B.Tech/M.Tech/PhD) existed twice, here and in examination; it now lives once in programme_scope. Examination's numbers are unchanged after that dedupe: grade summary 202/21/0/211, grade status 209/22/0/219.

Pre-existing failures found, not touched

Each fails identically for acadadmin with the same payload, so they predate this branch: create_batch → 500 Field 'id' expected a number; sync_batches_to_configuration → 500 duplicate key; fix_stuck_reported_students → 500 Cannot resolve keyword 'first_name', a field that model does not have — that view cannot ever have worked.

manage.py check clean, no missing migrations, no new migrations needed.

…nnouncement holes

Checking the new roles against a copy of production turned up three gaps left
by the first pass.

A role-targeted announcement reached nobody. The recipient filter required
every recipient to be a student of the sender's programme, so faculty failed
it: an Acad UG announcement to Professor was created and notified 0 people
where acadadmin notified 11. scope_recipients now drops out-of-scope students
and keeps anyone who is not a student, since faculty and staff are not bound to
a programme. Programme targeting is unchanged, and "everyone" now reaches every
non-student plus the sender's own students.

The two compose helpers stayed acadadmin-only, so the programme roles could
submit an announcement through the API but could not open the form that builds
one. Both now accept them, and the recipient search is scoped before its slice,
so a programme admin cannot pick a student whose notification would then be
dropped on send.

The 26 student-admission views in views_student_management.py were closed to
the programme roles, which left Upcoming Batches in their sidebar with a 403
behind it. All 26 are now open and scoped: lists, exports and upload history
narrow to the role's own level, per-record reads and writes refuse a record
from another level, and the create/upload/seat-configuration paths validate the
programme they are asked to act on. The bulk status update names the ids it
refuses instead of skipping them silently, and only judges ids from the UG/PG
table -- PhD records have their own ids, and the per-student call guards itself.
Consolidating duplicate curriculums or batches is confined to in-scope records,
so a programme admin cannot merge another level's data away.

Verified against production-shaped data: list_students 611/144/0 against 755
unscoped, sync_batch_data and curriculum status 30/13/0 against 43, duplicate
curriculums 5/5/0 against 10, and the UG and PG exports each refused to the
other role. Every partition sums to the unscoped total.

Two helpers were wrong rather than missing: scope_admission_records filtered on
programme_type, a field only the UG/PG model has, and the programme-name table
existed twice. Both now live once, in programme_scope.
@vikrantwiz02
vikrantwiz02 merged commit 2bbc303 into FusionIIIT:prod/acad-react Aug 18, 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