<?php namespace App\Http\Controllers; use App\Models\Role; use App\Models\SubjectTeacher; use App\Repositories\ClassSection\ClassSectionInterface; use App\Repositories\Diary\DiaryInterface; use App\Repositories\DiaryCategory\DiaryCategoryInterface; use App\Repositories\DiaryStudent\DiaryStudentInterface; use App\Repositories\SessionYear\SessionYearInterface; use App\Repositories\Student\StudentInterface; use App\Repositories\Subject\SubjectInterface; use App\Repositories\SubjectTeacher\SubjectTeacherInterface; use App\Repositories\User\UserInterface; use App\Services\BootstrapTableService; use App\Services\CachingService; use App\Services\ResponseService; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; use Storage; use Str; use Throwable; class DiaryController extends Controller { /** * Display a listing of the resource. */ private ClassSectionInterface $classSection; private SessionYearInterface $sessionYear; private DiaryCategoryInterface $diaryCategories; private SubjectInterface $subject; private StudentInterface $student; private UserInterface $user; private DiaryInterface $diary; private DiaryStudentInterface $diaryStudent; private CachingService $cache; private SubjectTeacherInterface $subjectTeacher; public function __construct(ClassSectionInterface $classSection, SessionYearInterface $sessionYear, DiaryCategoryInterface $diaryCategories, SubjectInterface $subject, UserInterface $user, StudentInterface $student, CachingService $cache, DiaryInterface $diary, DiaryStudentInterface $diaryStudent, SubjectTeacherInterface $subjectTeacher) { $this->classSection = $classSection; $this->sessionYear = $sessionYear; $this->diaryCategories = $diaryCategories; $this->subject = $subject; $this->user = $user; $this->student = $student; $this->cache = $cache; $this->diary = $diary; $this->diaryStudent = $diaryStudent; $this->subjectTeacher = $subjectTeacher; } public function index() { ResponseService::noPermissionThenRedirect('student-diary-list'); // $class_sections = $this->classSection->all(['*'], ['class', 'class.stream', 'section', 'medium']); $sessionYearId = $this->cache->getSessionYear()->id; $class_sections = $this->classSection->builder()->with('section', 'medium') ->with(['class' => function ($q) use ($sessionYearId) { $q->with('stream', 'shift') ->with(['class_teachers' => function ($query) use ($sessionYearId) { $query->where('session_year_id', $sessionYearId); }]); }]) ->with(['subject_teachers' => function ($query) use ($sessionYearId) { $query->where('session_year_id', $sessionYearId)->groupBy('subject_id')->with('subject'); }]) ->get(); $diaryCategories = $this->diaryCategories->all(); $current_user = null; if (Auth::user()->role == 'Teacher') { $current_user = Auth::user()->id; } // Get current semester data for filtering subjects $currentSemester = $this->cache->getSemester(); $currentSemesterId = ($currentSemester && isset($currentSemester->id)) ? $currentSemester->id : null; return view('diary.index', compact('class_sections', 'diaryCategories', 'current_user', 'currentSemesterId')); } public function changeSubjectsByClassSection(Request $request) { $sessionYearId = $this->cache->getSessionYear()->id; $class_section_id = $request->class_section_id; // if ($class_section_id) { // dd($class_section_id); // } $subjectTeachers = $this->subjectTeacher->builder()->where('session_year_id', $sessionYearId)->where('class_section_id', $class_section_id)->with('subject:id,name,type')->get(); return response()->json($subjectTeachers); } public function showStudents(Request $request) { ResponseService::noPermissionThenRedirect('student-diary-list'); // ResponseService::noPermissionThenRedirect('student-list'); $offset = request('offset', 0); $limit = request('limit', 10); $sort = request('sort', 'id'); $order = request('order', 'ASC'); $search = request('search'); // $class_section_ids = request('class_section_id'); $sessionYearId = $this->cache->getSessionYear()->id; $sql = $this->student->builder()->where('session_year_id', $sessionYearId)->where(function ($query) { $query->where('application_type', 'offline') ->orWhere(function ($q) { $q->where('application_type', 'online') ->where('application_status', 1); // Only online applications with status 1 }); }) ->with('user', 'class_section') ->where(function ($query) use ($search) { $query->when($search, function ($query) use ($search) { $query->where(function ($query) use ($search) { $query->orWhere('roll_number', 'LIKE', "%$search%") ->orWhereHas('user', function ($q) use ($search) { $q->where('first_name', 'LIKE', "%$search%") ->orwhere('last_name', 'LIKE', "%$search%") ->orWhereRaw("concat(first_name,' ',last_name) LIKE '%" . $search . "%'"); }); }); }); //class section filter data }) ->when(request()->filled('class_section_id'), function ($query) { $query->where('class_section_id', request('class_section_id')); }) ->when(request()->filled('session_year_id'), function ($query) { $query->where('session_year_id', request('session_year_id')); }); $user = Auth::user(); if ($user->hasRole('Teacher')) { $sql->WhereHas('class_section.subject_teachers', function ($query) use ($user) { $query->where('teacher_id', $user->id); }); } if ($request->show_deactive) { $sql = $sql->whereHas('user', function ($query) { $query->where('status', 0)->withTrashed(); }); } else { $sql = $sql->whereHas('user', function ($query) { $query->where('status', 1); }); } $total = $sql->count(); if (!empty($request->class_section_id)) { $sql = $sql->orderBy('roll_number', 'ASC'); } else { $sql = $sql->orderBy($sort, $order); } if ($offset >= $total && $total > 0) { $lastPage = floor(($total - 1) / $limit) * $limit; // calculate last page offset $offset = $lastPage; } $sql->skip($offset)->take($limit); $res = $sql->get(); $bulkData = array(); $bulkData['total'] = $total; $rows = array(); $no = 1; foreach ($res as $row) { $tempRow = $row->toArray(); $tempRow['no'] = $no++; $rows[] = $tempRow; } $bulkData['rows'] = $rows; return response()->json($bulkData); } /** * Show the form for creating a new resource. */ public function create() { // } /** * Store a newly created resource in storage. */ public function store(Request $request) { ResponseService::noPermissionThenSendJson('student-diary-create'); $validator = Validator::make($request->all(), [ 'diary_category_id' => 'required', 'title' => 'required|string|max:255', 'description' => 'required|string', 'student_class_section_map' => 'required|not_in:0,null', 'date' => 'required|date', ]); if ($validator->fails()) { ResponseService::errorResponse($validator->errors()->first()); } try { DB::beginTransaction(); $studentsClassSections = json_decode($request->student_class_section_map, true); if (empty($studentsClassSections)) { ResponseService::errorResponse('Please select Students'); } $sessionYear = $this->cache->getSessionYear(); $data = [ 'diary_category_id' => $request->diary_category_id, 'title' => $request->title, 'user_id' => Auth::id(), 'subject_id' => $request->subject_id, 'session_year_id' => $sessionYear->id, 'description' => $request->description, 'date' => $request->date, ]; $diary = $this->diary->create($data); /* ------------------------------------------------- | CORE LOGIC (UNCHANGED) -------------------------------------------------*/ $notifyUser = []; $studentsData = []; foreach ($studentsClassSections as $student_id => $class_section_id) { $studentsData[] = [ 'diary_id' => $diary->id, 'student_id' => $student_id, 'class_section_id' => $class_section_id, ]; $notifyUser[] = [ 'student_id' => $student_id, 'class_section_id' => $class_section_id, ]; } $this->diaryStudent->createBulk($studentsData); /* ================================================= | 🔒 NOTIFICATION FILTER (ONLY CHANGE) =================================================*/ $finalStudentIds = []; if (!$request->subject_id) { // General diary → notify all $finalStudentIds = collect($notifyUser)->pluck('student_id')->toArray(); } else { foreach ($notifyUser as $entry) { $studentId = $entry['student_id']; $classSectionId = $entry['class_section_id']; // Resolve class_id $classId = DB::table('class_sections') ->where('id', $classSectionId) ->value('class_id'); if (!$classId) { continue; } // Resolve class_subject for this class $classSubject = DB::table('class_subjects') ->where('class_id', $classId) ->where('subject_id', $request->subject_id) ->first(); // Subject not in this section/class → skip if (!$classSubject) { continue; } // Compulsory → notify if ($classSubject->type === 'Compulsory') { $finalStudentIds[] = $studentId; continue; } // Elective → notify only if assigned $isAssigned = DB::table('student_subjects') ->where('student_id', $studentId) ->where('class_subject_id', $classSubject->id) ->exists(); if ($isAssigned) { $finalStudentIds[] = $studentId; } } } /* ------------------------------------------------- | BUILD PAYLOADS (UNCHANGED STRUCTURE) -------------------------------------------------*/ $students = $this->student->builder() ->whereIn('user_id', $finalStudentIds) ->with('user') ->get(['id', 'user_id', 'guardian_id']); $allPayloads = []; $title = "New Diary Note Received"; $body = $request->title; $type = 'Diary'; foreach ($students as $student) { $childId = $student->id; $studentUid = $student->user_id; $guardianId = $student->guardian_id; // Guardian if ($guardianId) { $allPayloads = array_merge( $allPayloads, buildPayloads( [$guardianId], $title, $body, $type, [ 'child_id' => $childId, 'student_id' => $studentUid, ] ) ); } // Student $allPayloads = array_merge( $allPayloads, buildPayloads( [$studentUid], $title, $body, $type, [ 'student_id' => $studentUid, ] ) ); } DB::commit(); if (!empty($allPayloads)) { sendBulk($allPayloads); } ResponseService::successResponse('Data Stored Successfully'); } catch (Throwable $e) { if ( Str::contains($e->getMessage(), [ 'does not exist', 'file_get_contents' ]) ) { DB::commit(); ResponseService::warningResponse( "Data Stored successfully. But App push notification not send." ); } else { DB::rollBack(); ResponseService::logErrorResponse($e, "Diary Controller -> Store Method"); ResponseService::errorResponse(); } } } /** * Display the specified resource. */ public function show(string $id) { // dd(Auth::user()->hasRole('Teacher')); ResponseService::noPermissionThenRedirect('student-diary-list'); $loggedInUser = Auth::user(); $offset = request('offset', 0); $limit = request('limit', 10); $sort = request('sort', 'id'); $order = request('order', 'DESC'); $search = request('search'); $class_section_id = request('class_section_id'); $sessionYearId = $this->cache->getSessionYear()->id; $sql = $this->diary->builder() ->where('session_year_id', $sessionYearId) ->with('session_year', 'diary_category', 'subject', 'diary_students.student', 'diary_students.class_section', 'diary_students.class_section.section', 'diary_students.class_section.medium', 'diary_students.class_section.class.shift', 'diary_students.class_section.class.stream', 'diary_students.class_section.class') ->where(function ($query) use ($search) { $query->when($search, function ($query) use ($search) { $query->where('id', 'LIKE', "%$search%") ->orWhere('description', 'LIKE', "%$search%") ->orWhere('title', 'LIKE', "%$search%") ->orWhereHas('session_year', function ($q) use ($search) { $q->where('name', 'LIKE', "%$search%"); }) ->orWhereHas('diary_category', function ($q) use ($search) { $q->where('name', 'LIKE', "%$search%"); }) ->orWhereHas('subject', function ($q) use ($search) { $q->where('name', 'LIKE', "%$search%"); }) ->orWhereHas('diary_students.student', function ($q) use ($search) { $q->where('first_name', 'LIKE', "%$search%") ->orWhere('last_name', 'LIKE', "%$search%") ->orWhereRaw("concat(first_name,' ',last_name) LIKE '%" . $search . "%'"); }); }); }) ->when(request()->filled('class_section_id'), function ($query) { $classId = request('class_section_id'); $query->whereHas('diary_students', function ($q) use ($classId) { $q->where('class_section_id', $classId); }); }) ->when(request()->filled('filter_diary_type'), function ($query) { $type = request('filter_diary_type'); $query->whereHas('diary_category', function ($q) use ($type) { $q->where('type', $type); }); }) ->when(!empty($showDeleted), function ($query) { $query->onlyTrashed(); }); if ($loggedInUser->hasRole('Teacher')) { if ($class_section_id) { $subjectIds = SubjectTeacher::where('teacher_id', $loggedInUser->id)->where('class_section_id', $class_section_id ?? null)->pluck('subject_id')->toArray(); $sql->whereIn('subject_id', $subjectIds); } } if ($loggedInUser->hasRole('School Admin')) { $sql->with('user'); } $total = $sql->count(); if ($offset >= $total && $total > 0) { $lastPage = floor(($total - 1) / $limit) * $limit; // calculate last page offset $offset = $lastPage; } $sql->orderBy($sort, $order)->skip($offset)->take($limit); $res = $sql->get(); $bulkData = []; $bulkData['total'] = $total; $rows = []; $no = 1; foreach ($res as $row) { $stu = trans('Click here to view'); $operate = ''; $operate .= BootstrapTableService::deleteButton(route('diary.destroy', $row->id)); $tempRow = $row->toArray(); $tempRow['no'] = $no++; $tempRow['student'] = $stu; $tempRow['operate'] = $operate; $rows[] = $tempRow; } $bulkData['rows'] = $rows; return response()->json($bulkData); } /** * Show the form for editing the specified resource. */ public function edit(string $id) { // } /** * Update the specified resource in storage. */ public function update(Request $request, string $id) { // } /** * Remove the specified resource from storage. */ public function destroy(string $id) { ResponseService::noPermissionThenSendJson('student-diary-delete'); try { DB::beginTransaction(); // $this->diaryCategory->findOnlyTrashedById($id); $this->diary->findTrashedById($id)->forceDelete(); DB::commit(); ResponseService::successResponse('Data Deleted Successfully'); } catch (Throwable $e) { DB::rollBack(); ResponseService::logErrorResponse($e, 'Diary Controller ->destroy Method'); ResponseService::errorResponse(); } } public function removeStudent($diaryId, $id) { ResponseService::noPermissionThenSendJson('student-diary-delete'); $studentCount = $this->diaryStudent->builder() ->where(['diary_id' => $diaryId])->count(); // dd('diary id', $diaryId, 'student', $studentCount,'id', $id); if ($studentCount == 1 || $studentCount < 2) { $this->destroy($diaryId); } else { try { DB::beginTransaction(); // $this->diaryCategory->findOnlyTrashedById($id); $this->diaryStudent->findTrashedById($id)->forceDelete(); DB::commit(); ResponseService::successResponse('Student Removed Successfully'); } catch (Throwable $e) { DB::rollBack(); ResponseService::logErrorResponse($e, 'Diary Controller ->removeStudent Method'); ResponseService::errorResponse(); } } } }