fix endpoints

This commit is contained in:
root
2026-03-11 23:32:54 -04:00
parent 863e330dd8
commit 0f39dbee62
17 changed files with 2066 additions and 7 deletions
@@ -68,6 +68,31 @@ class FinalController extends BaseApiController
return response()->json(['ok' => true, 'updated' => $count]);
}
public function bySchoolYear(Request $request): JsonResponse
{
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'school_year' => ['required', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$data = $this->service->listBySchoolYear('final_exam', $payload['school_year']);
return response()->json([
'ok' => true,
'school_year' => $data['schoolYear'],
'count' => count($data['rows']),
'rows' => $data['rows'],
]);
}
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
{
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
@@ -86,6 +86,31 @@ class HomeworkController extends BaseApiController
return response()->json(['ok' => true, 'homework_index' => $nextIndex]);
}
public function bySchoolYear(Request $request): JsonResponse
{
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'school_year' => ['required', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$data = $this->service->listBySchoolYear($payload['school_year']);
return response()->json([
'ok' => true,
'school_year' => $data['schoolYear'],
'count' => count($data['rows']),
'rows' => $data['rows'],
]);
}
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
{
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
@@ -68,6 +68,31 @@ class MidtermController extends BaseApiController
return response()->json(['ok' => true, 'updated' => $count]);
}
public function bySchoolYear(Request $request): JsonResponse
{
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'school_year' => ['required', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$data = $this->service->listBySchoolYear('midterm_exam', $payload['school_year']);
return response()->json([
'ok' => true,
'school_year' => $data['schoolYear'],
'count' => count($data['rows']),
'rows' => $data['rows'],
]);
}
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
{
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
@@ -71,6 +71,31 @@ class ParticipationController extends BaseApiController
return response()->json(['ok' => true, 'updated' => $count]);
}
public function bySchoolYear(Request $request): JsonResponse
{
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'school_year' => ['required', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$data = $this->service->listBySchoolYear($payload['school_year']);
return response()->json([
'ok' => true,
'school_year' => $data['schoolYear'],
'count' => count($data['rows']),
'rows' => $data['rows'],
]);
}
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
{
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
@@ -86,6 +86,31 @@ class ProjectController extends BaseApiController
return response()->json(['ok' => true, 'project_index' => $nextIndex]);
}
public function bySchoolYear(Request $request): JsonResponse
{
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'school_year' => ['required', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$data = $this->service->listBySchoolYear($payload['school_year']);
return response()->json([
'ok' => true,
'school_year' => $data['schoolYear'],
'count' => count($data['rows']),
'rows' => $data['rows'],
]);
}
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
{
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
@@ -86,6 +86,31 @@ class QuizController extends BaseApiController
return response()->json(['ok' => true, 'quiz_index' => $nextIndex]);
}
public function bySchoolYear(Request $request): JsonResponse
{
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'school_year' => ['required', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$data = $this->service->listBySchoolYear($payload['school_year']);
return response()->json([
'ok' => true,
'school_year' => $data['schoolYear'],
'count' => count($data['rows']),
'rows' => $data['rows'],
]);
}
private function refreshSemesterScores(int $classSectionId, string $semester, string $schoolYear): void
{
$studentInfo = Student::getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear, (int) (auth()->id() ?? 0));
@@ -14,6 +14,14 @@ use App\Http\Resources\Students\StudentAssignmentResource;
use App\Http\Resources\Students\StudentClassSectionResource;
use App\Http\Resources\Students\StudentRemovedResource;
use App\Http\Resources\Students\StudentScoreCardRowResource;
use App\Models\AttendanceRecord;
use App\Models\ClassSection;
use App\Models\EmergencyContact;
use App\Models\Incident;
use App\Models\SemesterScore;
use App\Models\Student;
use App\Models\StudentClass;
use App\Models\User;
use App\Services\Students\StudentAssignmentService;
use App\Services\Students\StudentAutoDistributionService;
use App\Services\Students\StudentDirectoryService;
@@ -21,6 +29,10 @@ use App\Services\Students\StudentProfileService;
use App\Services\Students\StudentScoreCardService;
use App\Services\Students\StudentStatusService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
class StudentController extends BaseApiController
{
@@ -50,6 +62,104 @@ class StudentController extends BaseApiController
]);
}
public function index(Request $request): JsonResponse
{
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'school_year' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$data = $this->directoryService->listStudents($payload['school_year'] ?? null);
return response()->json([
'ok' => true,
'students' => $data['students'],
'school_year' => $data['schoolYear'],
'current_year' => $data['currentYear'],
]);
}
public function show(int $studentId): JsonResponse
{
$student = Student::query()->find($studentId);
if (!$student) {
return response()->json(['ok' => false, 'message' => 'Student not found.'], 404);
}
return response()->json([
'ok' => true,
'student' => $student->only([
'id',
'school_id',
'firstname',
'lastname',
'dob',
'age',
'gender',
'is_active',
'registration_grade',
'is_new',
'photo_consent',
'parent_id',
'registration_date',
'tuition_paid',
'rfid_tag',
'semester',
'year_of_registration',
'school_year',
]),
]);
}
public function store(Request $request): JsonResponse
{
$data = array_merge($request->query->all(), $request->all(), $request->json()->all());
$validator = Validator::make($data, [
'school_id' => ['nullable', 'string', 'max:50'],
'firstname' => ['required', 'string', 'max:150'],
'lastname' => ['required', 'string', 'max:150'],
'dob' => ['nullable', 'date'],
'age' => ['nullable', 'integer', 'min:0'],
'gender' => ['nullable', 'string', 'max:20'],
'is_active' => ['nullable', 'boolean'],
'registration_grade' => ['nullable', 'string', 'max:50'],
'is_new' => ['nullable', 'boolean'],
'photo_consent' => ['nullable', 'boolean'],
'parent_id' => ['nullable', 'integer', 'min:1'],
'registration_date' => ['nullable', 'date'],
'tuition_paid' => ['nullable', 'boolean'],
'rfid_tag' => ['nullable', 'string', 'max:100'],
'semester' => ['nullable', 'string', 'max:50'],
'year_of_registration' => ['nullable', 'integer', 'min:1900'],
'school_year' => ['required', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$student = Student::query()->create($payload);
if (empty($student->school_id)) {
$student->school_id = $this->generateSchoolId($student->id);
$student->save();
}
return response()->json(['ok' => true, 'student' => $student], 201);
}
public function assignClass(StudentAssignClassRequest $request): JsonResponse
{
$payload = $request->validated();
@@ -140,6 +250,447 @@ class StudentController extends BaseApiController
return response()->json($result + ['ok' => (bool) $result['ok']], $status);
}
public function destroy(int $studentId): JsonResponse
{
$student = Student::query()->find($studentId);
if (!$student) {
return response()->json(['ok' => false, 'message' => 'Student not found.'], 404);
}
$student->update(['is_active' => 0]);
return response()->json(['ok' => true]);
}
public function classes(Request $request, int $studentId): JsonResponse
{
$validator = Validator::make($request->query->all(), [
'school_year' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$schoolYear = $validator->validated()['school_year'] ?? null;
$rows = StudentClass::query()
->select('student_class.*', 'cs.class_section_name')
->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'student_class.class_section_id')
->where('student_class.student_id', $studentId)
->when($schoolYear !== null && $schoolYear !== '', fn ($q) => $q->where('student_class.school_year', $schoolYear))
->orderBy('cs.class_section_name')
->get()
->toArray();
return response()->json([
'ok' => true,
'student_id' => $studentId,
'school_year' => $schoolYear,
'classes' => $rows,
]);
}
public function assignClassForStudent(Request $request, int $studentId): JsonResponse
{
$data = array_merge($request->all(), $request->json()->all());
$validator = Validator::make($data, [
'student_id' => ['required', 'integer', 'min:1'],
'class_section_id' => ['nullable', 'integer', 'min:1'],
'class_section_ids' => ['nullable', 'array'],
'class_section_ids.*' => ['integer', 'min:1'],
'is_event_only' => ['nullable', 'boolean'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
if ((int) $payload['student_id'] !== $studentId) {
return response()->json([
'message' => 'Validation failed.',
'errors' => ['student_id' => ['student_id does not match the route studentId.']],
], 422);
}
$ids = $payload['class_section_ids'] ?? [];
if (empty($ids) && isset($payload['class_section_id'])) {
$ids = [(int) $payload['class_section_id']];
}
$result = $this->assignmentService->assignClasses(
$studentId,
$ids,
(bool) ($payload['is_event_only'] ?? false),
(int) (auth()->id() ?? 0)
);
$status = $result['ok'] ? 200 : 422;
return response()->json($result + ['ok' => (bool) $result['ok']], $status);
}
public function removeClassForStudent(int $studentId, int $classSectionId): JsonResponse
{
$result = $this->assignmentService->removeClass(
$studentId,
$classSectionId,
(int) (auth()->id() ?? 0)
);
$status = $result['ok'] ? 200 : 422;
return response()->json($result + ['ok' => (bool) $result['ok']], $status);
}
public function promote(Request $request, int $studentId): JsonResponse
{
$data = array_merge($request->all(), $request->json()->all());
$validator = Validator::make($data, [
'class_section_id' => ['required', 'integer', 'min:1'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$result = $this->assignmentService->assignClasses(
$studentId,
[(int) $payload['class_section_id']],
false,
(int) (auth()->id() ?? 0)
);
$status = $result['ok'] ? 200 : 422;
return response()->json($result + ['ok' => (bool) $result['ok']], $status);
}
public function attendance(Request $request, int $studentId): JsonResponse
{
$validator = Validator::make($request->query->all(), [
'school_year' => ['nullable', 'string', 'max:50'],
'semester' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$rows = AttendanceRecord::query()
->where('student_id', $studentId)
->when(!empty($payload['school_year']), fn ($q) => $q->where('school_year', $payload['school_year']))
->when(!empty($payload['semester']), fn ($q) => $q->where('semester', $payload['semester']))
->orderBy('school_year', 'desc')
->orderBy('semester', 'desc')
->get()
->toArray();
return response()->json([
'ok' => true,
'student_id' => $studentId,
'rows' => $rows,
]);
}
public function incidents(Request $request, int $studentId): JsonResponse
{
$validator = Validator::make($request->query->all(), [
'school_year' => ['nullable', 'string', 'max:50'],
'semester' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$rows = Incident::query()
->where('student_id', $studentId)
->when(!empty($payload['school_year']), fn ($q) => $q->where('school_year', $payload['school_year']))
->when(!empty($payload['semester']), fn ($q) => $q->where('semester', $payload['semester']))
->orderByDesc('incident_datetime')
->get()
->toArray();
return response()->json([
'ok' => true,
'student_id' => $studentId,
'rows' => $rows,
]);
}
public function scores(Request $request, int $studentId): JsonResponse
{
$validator = Validator::make($request->query->all(), [
'school_year' => ['nullable', 'string', 'max:50'],
'semester' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$rows = SemesterScore::query()
->where('student_id', $studentId)
->when(!empty($payload['school_year']), fn ($q) => $q->where('school_year', $payload['school_year']))
->when(!empty($payload['semester']), fn ($q) => $q->where('semester', $payload['semester']))
->orderBy('school_year', 'desc')
->orderBy('semester', 'desc')
->get()
->toArray();
return response()->json([
'ok' => true,
'student_id' => $studentId,
'rows' => $rows,
]);
}
public function notes(int $studentId): JsonResponse
{
return response()->json([
'ok' => true,
'student_id' => $studentId,
'rows' => [],
]);
}
public function parents(int $studentId): JsonResponse
{
$student = Student::query()->find($studentId);
if (!$student) {
return response()->json(['ok' => false, 'message' => 'Student not found.'], 404);
}
$parent = null;
if (!empty($student->parent_id)) {
$parent = User::query()
->select(['id', 'firstname', 'lastname', 'email', 'cellphone'])
->find((int) $student->parent_id);
}
return response()->json([
'ok' => true,
'student_id' => $studentId,
'parent' => $parent,
]);
}
public function emergencyContacts(int $studentId): JsonResponse
{
$student = Student::query()->find($studentId);
if (!$student) {
return response()->json(['ok' => false, 'message' => 'Student not found.'], 404);
}
$query = EmergencyContact::query();
if (Schema::hasColumn('emergency_contacts', 'student_id')) {
$query->where('student_id', $studentId);
}
if (!empty($student->parent_id)) {
$query->orWhere('parent_id', $student->parent_id);
}
$rows = $query
->orderBy('emergency_contact_name')
->get()
->toArray();
return response()->json([
'ok' => true,
'student_id' => $studentId,
'rows' => $rows,
]);
}
public function addEmergencyContact(Request $request, int $studentId): JsonResponse
{
$student = Student::query()->find($studentId);
if (!$student) {
return response()->json(['ok' => false, 'message' => 'Student not found.'], 404);
}
$data = array_merge($request->all(), $request->json()->all());
$validator = Validator::make($data, [
'name' => ['required', 'string', 'max:150'],
'cellphone' => ['required', 'string', 'max:30'],
'email' => ['nullable', 'email', 'max:150'],
'relation' => ['nullable', 'string', 'max:80'],
'semester' => ['nullable', 'string', 'max:50'],
'school_year' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$payload = $validator->validated();
$create = [
'parent_id' => $student->parent_id,
'emergency_contact_name' => $payload['name'],
'cellphone' => $payload['cellphone'],
'email' => $payload['email'] ?? null,
'relation' => $payload['relation'] ?? null,
'semester' => $payload['semester'] ?? null,
'school_year' => $payload['school_year'] ?? null,
];
if (Schema::hasColumn('emergency_contacts', 'student_id')) {
$create['student_id'] = $studentId;
}
$row = EmergencyContact::query()->create($create);
return response()->json(['ok' => true, 'row' => $row], 201);
}
public function updateEmergencyContact(Request $request, int $studentId, int $contactId): JsonResponse
{
$student = Student::query()->find($studentId);
if (!$student) {
return response()->json(['ok' => false, 'message' => 'Student not found.'], 404);
}
$data = array_merge($request->all(), $request->json()->all());
$validator = Validator::make($data, [
'name' => ['nullable', 'string', 'max:150'],
'cellphone' => ['nullable', 'string', 'max:30'],
'email' => ['nullable', 'email', 'max:150'],
'relation' => ['nullable', 'string', 'max:80'],
'semester' => ['nullable', 'string', 'max:50'],
'school_year' => ['nullable', 'string', 'max:50'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$contact = EmergencyContact::query()->find($contactId);
if (!$contact) {
return response()->json(['ok' => false, 'message' => 'Contact not found.'], 404);
}
$payload = $validator->validated();
$contact->update(array_filter([
'emergency_contact_name' => $payload['name'] ?? null,
'cellphone' => $payload['cellphone'] ?? null,
'email' => $payload['email'] ?? null,
'relation' => $payload['relation'] ?? null,
'semester' => $payload['semester'] ?? null,
'school_year' => $payload['school_year'] ?? null,
], static fn ($v) => $v !== null));
return response()->json(['ok' => true, 'row' => $contact]);
}
public function updateRfid(Request $request, int $studentId): JsonResponse
{
$validator = Validator::make($request->all(), [
'rfid_tag' => ['required', 'string', 'max:100'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$student = Student::query()->find($studentId);
if (!$student) {
return response()->json(['ok' => false, 'message' => 'Student not found.'], 404);
}
$student->update(['rfid_tag' => $validator->validated()['rfid_tag']]);
return response()->json(['ok' => true]);
}
public function uploadPhoto(Request $request, int $studentId): JsonResponse
{
$validator = Validator::make($request->all(), [
'photo' => ['required', 'file', 'image', 'max:5120'],
]);
if ($validator->fails()) {
return response()->json([
'message' => 'Validation failed.',
'errors' => $validator->errors(),
], 422);
}
$student = Student::query()->find($studentId);
if (!$student) {
return response()->json(['ok' => false, 'message' => 'Student not found.'], 404);
}
$file = $request->file('photo');
$ext = $file->getClientOriginalExtension() ?: 'jpg';
$path = "student-photos/{$studentId}." . strtolower($ext);
Storage::disk('public')->putFileAs('student-photos', $file, "{$studentId}." . strtolower($ext));
return response()->json([
'ok' => true,
'photo_url' => Storage::disk('public')->url($path),
]);
}
public function photo(int $studentId): JsonResponse
{
$base = "student-photos/{$studentId}";
$candidates = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
$disk = Storage::disk('public');
foreach ($candidates as $ext) {
$path = $base . '.' . $ext;
if ($disk->exists($path)) {
return response()->json([
'ok' => true,
'photo_url' => $disk->url($path),
]);
}
}
return response()->json(['ok' => false, 'message' => 'Photo not found.'], 404);
}
private function generateSchoolId(int $studentId): string
{
$year = (int) date('y');
return 'STU' . $year . str_pad((string) $studentId, 4, '0', STR_PAD_LEFT);
}
public function scoreCard(int $studentId): JsonResponse
{
$result = $this->scoreCardService->scoreCard($studentId);