schoolYears = $schoolYears instanceof SchoolYearContextService ? $schoolYears : app(SchoolYearContextService::class); } public function listReports(User $user, array $filters): LengthAwarePaginator { $query = ClassProgressReport::query() ->with(['classSection', 'teacher']) ->orderBy($filters['sort_by'] ?? 'week_start', $filters['sort_dir'] ?? 'desc'); if (! $this->isAdmin($user)) { $relaxedSectionIds = TeacherClass::distinctSectionIdsForTeacher((int) $user->id); if (! empty($filters['class_section_id'])) { $sid = (int) $filters['class_section_id']; // Section filter: if this user has ever taught the section, show all rows for that section // (legacy DB often has `class_progress_reports` without matching current-year `teacher_class`). if (! in_array($sid, $relaxedSectionIds, true)) { $query->where('teacher_id', (int) $user->id); } } else { $query->where(function ($q) use ($user, $relaxedSectionIds) { $q->where('teacher_id', (int) $user->id); if ($relaxedSectionIds !== []) { $q->orWhereIn('class_section_id', $relaxedSectionIds); } }); } } elseif (! empty($filters['teacher_id'])) { $query->where('teacher_id', (int) $filters['teacher_id']); } if (! empty($filters['class_section_id'])) { $query->where('class_section_id', (int) $filters['class_section_id']); } if (! empty($filters['subject'])) { $query->where('subject', (string) $filters['subject']); } if (! empty($filters['status'])) { $query->where('status', (string) $filters['status']); } if (! empty($filters['school_year']) && Schema::hasColumn('class_progress_reports', 'school_year')) { $query->where('school_year', (string) $filters['school_year']); } if (! empty($filters['semester']) && Schema::hasColumn('class_progress_reports', 'semester')) { $query->where('semester', (string) $filters['semester']); } if (! empty($filters['week_start'])) { $query->whereDate('week_start', '>=', $filters['week_start']); } if (! empty($filters['week_end'])) { $query->whereDate('week_end', '<=', $filters['week_end']); } $perPage = (int) ($filters['per_page'] ?? 20); return $query->paginate($perPage); } public function getReport(User $user, int $reportId): ClassProgressReport { $report = ClassProgressReport::query()->with('classSection')->findOrFail($reportId); if ($this->isAdmin($user)) { return $report; } if ($this->viewerMayAccessReport($user, $report)) { return $report; } abort(404); } public function weeklyReports(User $user, ClassProgressReport $report): array { $query = ClassProgressReport::query() ->with('classSection') ->where('class_section_id', $report->class_section_id) ->whereDate('week_start', $report->week_start) ->orderBy('subject', 'asc'); // Non-admins reach this only after policy `view` passed on the anchor report (author or teaches section). $rows = $query->get(); $attachments = $this->attachmentMap($rows->pluck('id')->all()); return $rows->map(function (ClassProgressReport $row) use ($attachments) { $row->setAttribute('status_label', $this->statusLabel($row->status)); $row->setAttribute('attachments', $attachments[$row->id] ?? []); return $row; })->all(); } public function attachmentMap(array $reportIds): array { $reportIds = array_values(array_filter(array_map('intval', $reportIds))); if ($reportIds === []) { return []; } $rows = ClassProgressAttachment::query() ->whereIn('report_id', $reportIds) ->orderBy('id', 'asc') ->get(); $map = []; foreach ($rows as $row) { $map[$row->report_id][] = [ 'id' => $row->id, 'name' => $row->original_name ?: basename((string) $row->file_path), 'file_path' => $row->file_path, ]; } return $map; } public function teacherAssignments(User $user, ?string $schoolYear, ?string $semester): array { if ($schoolYear === null || $schoolYear === '') { $schoolYear = (string) (config('school.school_year') ?? ''); } return TeacherClass::getClassAssignmentsByUserId($user->id, $schoolYear, $semester); } public function meta(?string $schoolYear = null, ?string $semester = null): array { return $this->schoolYears->options($schoolYear, $semester); } private function statusLabel(?string $status): string { $options = (array) config('progress.status_options', []); return $options[$status] ?? 'Unknown'; } private function isAdmin(User $user): bool { $roles = $user->roles() ->pluck('roles.name') ->map(fn ($name) => strtolower((string) $name)) ->toArray(); foreach (['administrator', 'admin', 'principal', 'vice_principal', 'vice-principal'] as $role) { if (in_array($role, $roles, true)) { return true; } } return false; } /** * legacy `ClassProgressController::resolveAssignedTeacherIds`. * * @return list */ public function resolveAssignedTeacherIds(int $classSectionId): array { $schoolYear = (string) (Configuration::getConfig('school_year') ?? ''); if ($schoolYear === '' || $classSectionId <= 0) { return []; } $semester = (string) (Configuration::getConfig('semester') ?? ''); $rows = TeacherClass::assignedForSectionTerm($classSectionId, $semester, $schoolYear); if ($rows === []) { $rows = TeacherClass::assignedForSectionTerm($classSectionId, $semester, $schoolYear, null, false); } $ids = []; foreach ($rows as $row) { $id = (int) ($row['teacher_id'] ?? 0); if ($id > 0) { $ids[$id] = true; } } return array_map('intval', array_keys($ids)); } private function viewerMayAccessReport(User $user, ClassProgressReport $report): bool { if ((int) $report->teacher_id === (int) $user->id) { return true; } return in_array( (int) $report->class_section_id, TeacherClass::distinctSectionIdsForTeacher((int) $user->id), true ); } }