Skip to content

Introduce program-scoped student portal with leave application flow - #456

Merged
tuwafula merged 5 commits into
version-16from
version-16-hotfix
Jul 1, 2026
Merged

Introduce program-scoped student portal with leave application flow#456
tuwafula merged 5 commits into
version-16from
version-16-hotfix

Conversation

@tuwafula

@tuwafula tuwafula commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extends the education student portal so users with multiple program enrollments can choose an active program and see schedule, grades, and attendance, scoped to that program.

Program selection and scoped portal data

  • Add get_student_profile and get_program_context backend APIs to load student profile, all submitted enrollments, and student groups for the selected program
  • Refactor studentStore to load profile then program context sequentially; persist the selected program per student in localStorage
  • Add ProgramSelector in the navbar for multi-program users
  • Make Schedule, Grades, and Attendance reactive to program/student changes

Portal API cleanup and routing

  • Rename portal endpoints to get_student_profile / get_program_context and update the SPA store accordingly
  • Set role_home_page for Student and Guardian roles to edu-portal

Leave application refactor

  • Replace direct make_attendance_records calls with submitted Student Leave Application documents
  • Reset leave form fields after successful submission in Attendance.vue

tuwafula added 5 commits July 1, 2026 17:34
Add portal-specific student APIs so the SPA loads all submitted program
enrollments, lets the user choose the active program, and derives student
groups and page data from that selection instead of a single auto-detected
current enrollment.

Backend (education/education/api.py):
- Add get_portal_student_profile(student=None): whitelisted student profile
  (field whitelist), all submitted Program Enrollments, and suggested_program
  (active enrollment if valid, else most recent)
- Add get_portal_program_context(student=None, program=None): enrollment row
  plus student_groups for the selected program, permission-checked
- Add internal helpers: _resolve_portal_student, _get_submitted_program_enrollments,
  _resolve_default_program, _get_program_enrollment
- Refactor get_student_context(student, program=None) to delegate to the
  portal APIs while keeping the legacy response shape (current_program,
  student_groups, programs)

Frontend:
- Refactor studentStore to load profile then program context sequentially;
  expose programs, activeProgram, currentProgram, studentGroups
- Persist selected program per student in localStorage
  (education-active-program-{studentId})
- Add ProgramSelector.vue and mount it in Navbar for multi-program users
- Make Schedule, Grades, Attendance, and Fees reactive to program/student
  changes (watch store refs and reload resources)
- Remove Grades page-local program picker in favor of the global selector
- Add role_home_page for Student/Guardian -> edu-portal, rename portal
endpoints to get_student_profile/get_program_context, update the SPA store,
grant Student read access on Student Group
- Replace direct make_attendance_records calls with Student Leave Application docs
- Rename leave helpers to create_student_leave_application_based_on_*
- Reindent api.py tabs to spaces (file-wide formatting pass)
- Reset leave form fields after successful submission in Attendance.vue
- Drop Student role read permission on Student Group doctype
@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown

Confidence Score: 2/5

The leave application refactor has multiple functional regressions that would cause leaves to be silently not applied in production.

Both leave-application helpers call .save() rather than .submit(), meaning on_submit → update_attendance() never runs and no attendance records are created — the core feature introduced by this PR does not work. Additionally, apply_leave has no authorization check on the caller-supplied student identifier, and the student-group path drops all but the first group.

education/education/api.py — the leave application logic (save vs submit, missing permission check, single-group limitation)

Security Review

  • Missing authorization in apply_leave (education/education/api.py, line 813): the student value in leave_data comes from the client and is passed straight to a new document without any check_permission guard, allowing any authenticated user to create a leave application for any student.

Reviews (1): Last reviewed commit: "fix(api): check Student Group read permi..." | Re-trigger Greptile

Comment on lines +848 to +852
student_leave_application.reason = leave_data.get("reason")
student_leave_application.save()


def apply_leave_based_on_student_group(leave_data, program_name):
def create_student_leave_application_based_on_student_group(leave_data, program_name):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Leave application silently never applied — save() leaves the document in Draft (docstatus=0) and update_attendance() only runs from on_submit. Attendance records are never created, so the student's leave has no effect.

Suggested change
student_leave_application.reason = leave_data.get("reason")
student_leave_application.save()
def apply_leave_based_on_student_group(leave_data, program_name):
def create_student_leave_application_based_on_student_group(leave_data, program_name):
student_leave_application.reason = leave_data.get("reason")
student_leave_application.save()
student_leave_application.submit()
def create_student_leave_application_based_on_student_group(leave_data, program_name):

Comment on lines +862 to +866
student_leave_application.student_group = student_groups[0].get("label")
student_leave_application.from_date = leave_data.get("from_date")
student_leave_application.to_date = leave_data.get("to_date")
student_leave_application.reason = leave_data.get("reason")
student_leave_application.save()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Same .save() without .submit() issue as the course-schedule path — the leave application is saved as a Draft but on_submit → update_attendance() is never triggered, so no attendance records are created.

Suggested change
student_leave_application.student_group = student_groups[0].get("label")
student_leave_application.from_date = leave_data.get("from_date")
student_leave_application.to_date = leave_data.get("to_date")
student_leave_application.reason = leave_data.get("reason")
student_leave_application.save()
student_leave_application.student_group = student_groups[0].get("label")
student_leave_application.from_date = leave_data.get("from_date")
student_leave_application.to_date = leave_data.get("to_date")
student_leave_application.reason = leave_data.get("reason")
student_leave_application.save()
student_leave_application.submit()

@tuwafula
tuwafula merged commit 80eb86f into version-16 Jul 1, 2026
0 of 3 checks 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