Open the student-admission screens to the programme roles, and fix two announcement holes - #1958
Merged
vikrantwiz02 merged 1 commit intoAug 18, 2026
Conversation
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
Professorwas created and notified 0 people whereacadadminnotified 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.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_optionsandsearch_usersboth 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 searching25MCSAgets 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
adminUpcomingBatchesis in the three roles' nav, butlist_studentsand 25 sibling views inviews_student_management.pywere gated toacadadmin/Dean Academic. All 26 are now open and scoped:The gate is
("acadadmin", "Dean Academic") + SCOPED_ACAD_ROLES, deliberately notALL_ACAD_ROLES, which would also have admittedstudentacadadmin— a role that never had access here.Verified against production-shaped data
list_studentsupload_historysync_batch_databatches/curriculum_statusfind_duplicate_curriculumsdownload_students/ug/download_students/pg/Every partition sums to the unscoped total. On the write side, against a real PG record:
get_student/update_student_status/delete_studentrefuse 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)andset_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_recordsfiltered onprogramme_type, a field only the UG/PG model has, so it would have raisedFieldErroron PhD records; it now falls back to "PhD by model". The programme-name table (B.Tech/M.Tech/PhD) existed twice, here and inexamination; it now lives once inprogramme_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
acadadminwith the same payload, so they predate this branch:create_batch→ 500Field 'id' expected a number;sync_batches_to_configuration→ 500 duplicate key;fix_stuck_reported_students→ 500Cannot resolve keyword 'first_name', a field that model does not have — that view cannot ever have worked.manage.py checkclean, no missing migrations, no new migrations needed.