fix endpoints
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -81,7 +81,7 @@ class EmergencyContact extends BaseModel
|
||||
{
|
||||
$row = static::query()
|
||||
->where('parent_id', $parentId)
|
||||
->select(['emergency_contact_name', 'cellphone'])
|
||||
->select(['emergency_contact_name', 'cellphone', 'email'])
|
||||
->first();
|
||||
|
||||
return $row ? $row->toArray() : null;
|
||||
@@ -93,4 +93,4 @@ class EmergencyContact extends BaseModel
|
||||
->where('parent_id', $parentId)
|
||||
->get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,4 +131,34 @@ class ExamScoreService
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function listBySchoolYear(string $table, ?string $schoolYear): array
|
||||
{
|
||||
$schoolYear = $this->term->schoolYear($schoolYear);
|
||||
$schoolYearVariants = $this->term->schoolYearVariants($schoolYear);
|
||||
if (empty($schoolYearVariants)) {
|
||||
$schoolYearVariants = [$schoolYear];
|
||||
}
|
||||
|
||||
$rows = DB::table($table . ' as ex')
|
||||
->select([
|
||||
'ex.*',
|
||||
's.firstname as student_firstname',
|
||||
's.lastname as student_lastname',
|
||||
's.school_id as student_school_id',
|
||||
])
|
||||
->leftJoin('students as s', 's.id', '=', 'ex.student_id')
|
||||
->whereIn('ex.school_year', $schoolYearVariants)
|
||||
->orderBy('ex.class_section_id')
|
||||
->orderBy('s.lastname')
|
||||
->orderBy('s.firstname')
|
||||
->get()
|
||||
->map(fn ($row) => (array) $row)
|
||||
->all();
|
||||
|
||||
return [
|
||||
'rows' => $rows,
|
||||
'schoolYear' => $schoolYear,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,47 @@ class HomeworkScoreService
|
||||
];
|
||||
}
|
||||
|
||||
public function listBySchoolYear(?string $schoolYear): array
|
||||
{
|
||||
$schoolYear = $this->term->schoolYear($schoolYear);
|
||||
$schoolYearVariants = $this->term->schoolYearVariants($schoolYear);
|
||||
if (empty($schoolYearVariants)) {
|
||||
$schoolYearVariants = [$schoolYear];
|
||||
}
|
||||
|
||||
$rows = Homework::query()
|
||||
->select([
|
||||
'homework.id',
|
||||
'homework.student_id',
|
||||
'homework.school_id',
|
||||
'homework.class_section_id',
|
||||
'homework.updated_by',
|
||||
'homework.homework_index',
|
||||
'homework.score',
|
||||
'homework.comment',
|
||||
'homework.semester',
|
||||
'homework.school_year',
|
||||
'homework.created_at',
|
||||
'homework.updated_at',
|
||||
's.firstname as student_firstname',
|
||||
's.lastname as student_lastname',
|
||||
])
|
||||
->leftJoin('students as s', 's.id', '=', 'homework.student_id')
|
||||
->whereIn('homework.school_year', $schoolYearVariants)
|
||||
->orderBy('homework.class_section_id')
|
||||
->orderBy('s.lastname')
|
||||
->orderBy('s.firstname')
|
||||
->orderBy('homework.homework_index')
|
||||
->get()
|
||||
->map(fn ($row) => $row->toArray())
|
||||
->all();
|
||||
|
||||
return [
|
||||
'rows' => $rows,
|
||||
'schoolYear' => $schoolYear,
|
||||
];
|
||||
}
|
||||
|
||||
private function isLockedForAnySchoolYear(int $classSectionId, string $semester, array $schoolYearVariants): bool
|
||||
{
|
||||
foreach ($schoolYearVariants as $year) {
|
||||
|
||||
@@ -71,6 +71,45 @@ class ParticipationScoreService
|
||||
];
|
||||
}
|
||||
|
||||
public function listBySchoolYear(?string $schoolYear): array
|
||||
{
|
||||
$schoolYear = $this->term->schoolYear($schoolYear);
|
||||
$schoolYearVariants = $this->term->schoolYearVariants($schoolYear);
|
||||
if (empty($schoolYearVariants)) {
|
||||
$schoolYearVariants = [$schoolYear];
|
||||
}
|
||||
|
||||
$rows = Participation::query()
|
||||
->select([
|
||||
'participation.id',
|
||||
'participation.student_id',
|
||||
'participation.school_id',
|
||||
'participation.class_section_id',
|
||||
'participation.updated_by',
|
||||
'participation.score',
|
||||
'participation.comment',
|
||||
'participation.semester',
|
||||
'participation.school_year',
|
||||
'participation.created_at',
|
||||
'participation.updated_at',
|
||||
's.firstname as student_firstname',
|
||||
's.lastname as student_lastname',
|
||||
])
|
||||
->leftJoin('students as s', 's.id', '=', 'participation.student_id')
|
||||
->whereIn('participation.school_year', $schoolYearVariants)
|
||||
->orderBy('participation.class_section_id')
|
||||
->orderBy('s.lastname')
|
||||
->orderBy('s.firstname')
|
||||
->get()
|
||||
->map(fn ($row) => $row->toArray())
|
||||
->all();
|
||||
|
||||
return [
|
||||
'rows' => $rows,
|
||||
'schoolYear' => $schoolYear,
|
||||
];
|
||||
}
|
||||
|
||||
public function update(int $classSectionId, string $semester, string $schoolYear, array $scores, array $missingOk, int $updatedBy): int
|
||||
{
|
||||
if (GradingLock::isLocked($classSectionId, $semester, $schoolYear)) {
|
||||
|
||||
@@ -83,6 +83,47 @@ class ProjectScoreService
|
||||
];
|
||||
}
|
||||
|
||||
public function listBySchoolYear(?string $schoolYear): array
|
||||
{
|
||||
$schoolYear = $this->term->schoolYear($schoolYear);
|
||||
$schoolYearVariants = $this->term->schoolYearVariants($schoolYear);
|
||||
if (empty($schoolYearVariants)) {
|
||||
$schoolYearVariants = [$schoolYear];
|
||||
}
|
||||
|
||||
$rows = Project::query()
|
||||
->select([
|
||||
'project.id',
|
||||
'project.student_id',
|
||||
'project.school_id',
|
||||
'project.class_section_id',
|
||||
'project.updated_by',
|
||||
'project.project_index',
|
||||
'project.score',
|
||||
'project.comment',
|
||||
'project.semester',
|
||||
'project.school_year',
|
||||
'project.created_at',
|
||||
'project.updated_at',
|
||||
's.firstname as student_firstname',
|
||||
's.lastname as student_lastname',
|
||||
])
|
||||
->leftJoin('students as s', 's.id', '=', 'project.student_id')
|
||||
->whereIn('project.school_year', $schoolYearVariants)
|
||||
->orderBy('project.class_section_id')
|
||||
->orderBy('s.lastname')
|
||||
->orderBy('s.firstname')
|
||||
->orderBy('project.project_index')
|
||||
->get()
|
||||
->map(fn ($row) => $row->toArray())
|
||||
->all();
|
||||
|
||||
return [
|
||||
'rows' => $rows,
|
||||
'schoolYear' => $schoolYear,
|
||||
];
|
||||
}
|
||||
|
||||
public function update(int $classSectionId, string $semester, string $schoolYear, array $scores, array $missingOk, int $updatedBy): int
|
||||
{
|
||||
if (GradingLock::isLocked($classSectionId, $semester, $schoolYear)) {
|
||||
|
||||
@@ -82,6 +82,47 @@ class QuizScoreService
|
||||
];
|
||||
}
|
||||
|
||||
public function listBySchoolYear(?string $schoolYear): array
|
||||
{
|
||||
$schoolYear = $this->term->schoolYear($schoolYear);
|
||||
$schoolYearVariants = $this->term->schoolYearVariants($schoolYear);
|
||||
if (empty($schoolYearVariants)) {
|
||||
$schoolYearVariants = [$schoolYear];
|
||||
}
|
||||
|
||||
$rows = Quiz::query()
|
||||
->select([
|
||||
'quiz.id',
|
||||
'quiz.student_id',
|
||||
'quiz.school_id',
|
||||
'quiz.class_section_id',
|
||||
'quiz.updated_by',
|
||||
'quiz.quiz_index',
|
||||
'quiz.score',
|
||||
'quiz.comment',
|
||||
'quiz.semester',
|
||||
'quiz.school_year',
|
||||
'quiz.created_at',
|
||||
'quiz.updated_at',
|
||||
's.firstname as student_firstname',
|
||||
's.lastname as student_lastname',
|
||||
])
|
||||
->leftJoin('students as s', 's.id', '=', 'quiz.student_id')
|
||||
->whereIn('quiz.school_year', $schoolYearVariants)
|
||||
->orderBy('quiz.class_section_id')
|
||||
->orderBy('s.lastname')
|
||||
->orderBy('s.firstname')
|
||||
->orderBy('quiz.quiz_index')
|
||||
->get()
|
||||
->map(fn ($row) => $row->toArray())
|
||||
->all();
|
||||
|
||||
return [
|
||||
'rows' => $rows,
|
||||
'schoolYear' => $schoolYear,
|
||||
];
|
||||
}
|
||||
|
||||
public function update(int $classSectionId, string $semester, string $schoolYear, array $scores, array $missingOk, int $updatedBy): int
|
||||
{
|
||||
if (GradingLock::isLocked($classSectionId, $semester, $schoolYear)) {
|
||||
|
||||
@@ -66,7 +66,7 @@ class StudentDirectoryService
|
||||
'student_id' => $studentId,
|
||||
'name' => trim(($student['firstname'] ?? '') . ' ' . ($student['lastname'] ?? '')),
|
||||
'age' => $student['age'] ?? 'N/A',
|
||||
'email' => $emergencyInfo['emergency_contact_name'] ?? '',
|
||||
'email' => $emergencyInfo['email'] ?? '',
|
||||
'phone' => $emergencyInfo['cellphone'] ?? '',
|
||||
'registration_grade' => $student['registration_grade'] ?? 'N/A',
|
||||
'class_section_name' => $sectionDisplay !== '' ? $sectionDisplay : 'No class assigned',
|
||||
@@ -161,4 +161,43 @@ class StudentDirectoryService
|
||||
'school_year' => $schoolYear,
|
||||
];
|
||||
}
|
||||
|
||||
public function listStudents(?string $schoolYear = null): array
|
||||
{
|
||||
$context = $this->configService->context();
|
||||
$selectedYear = $schoolYear ?: (string) ($context['school_year'] ?? '');
|
||||
|
||||
$students = Student::query()
|
||||
->select([
|
||||
'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',
|
||||
])
|
||||
->when($selectedYear !== '', fn ($q) => $q->where('school_year', $selectedYear))
|
||||
->orderBy('lastname')
|
||||
->orderBy('firstname')
|
||||
->get()
|
||||
->toArray();
|
||||
|
||||
return [
|
||||
'students' => $students,
|
||||
'schoolYear' => $selectedYear,
|
||||
'currentYear' => (string) ($context['school_year'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
+15
-1
@@ -3,6 +3,8 @@
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
@@ -22,7 +24,19 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
'cleanup.scheduler' => \App\Http\Middleware\CleanupScheduler::class,
|
||||
'auth.docs' => \App\Http\Middleware\ApiDocsAuth::class,
|
||||
]);
|
||||
|
||||
$middleware->redirectGuestsTo(function (Request $request) {
|
||||
if ($request->is('api/*') || $request->expectsJson()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return route('login');
|
||||
});
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
$exceptions->render(function (AuthenticationException $e, Request $request) {
|
||||
if ($request->is('api/*') || $request->expectsJson()) {
|
||||
return response()->json(['message' => 'Unauthorized.'], 401);
|
||||
}
|
||||
});
|
||||
})->create();
|
||||
|
||||
+1090
-3
File diff suppressed because it is too large
Load Diff
@@ -390,6 +390,8 @@ Route::prefix('v1')->group(function () {
|
||||
});
|
||||
|
||||
Route::prefix('students')->group(function () {
|
||||
Route::get('/', [StudentApiController::class, 'index']);
|
||||
Route::post('/', [StudentApiController::class, 'store']);
|
||||
Route::get('assignments', [StudentApiController::class, 'assignments']);
|
||||
Route::post('assign-class', [StudentApiController::class, 'assignClass']);
|
||||
Route::post('remove-class', [StudentApiController::class, 'removeClass']);
|
||||
@@ -398,6 +400,24 @@ Route::prefix('v1')->group(function () {
|
||||
Route::post('auto-distribute', [StudentApiController::class, 'autoDistribute']);
|
||||
Route::get('promotion-totals', [StudentApiController::class, 'promotionTotals']);
|
||||
Route::patch('{studentId}', [StudentApiController::class, 'update']);
|
||||
Route::delete('{studentId}', [StudentApiController::class, 'destroy']);
|
||||
Route::get('{studentId}', [StudentApiController::class, 'show']);
|
||||
Route::get('{studentId}/classes', [StudentApiController::class, 'classes']);
|
||||
Route::post('{studentId}/classes', [StudentApiController::class, 'assignClassForStudent']);
|
||||
Route::delete('{studentId}/classes/{classSectionId}', [StudentApiController::class, 'removeClassForStudent']);
|
||||
Route::post('{studentId}/promote', [StudentApiController::class, 'promote']);
|
||||
Route::get('{studentId}/attendance', [StudentApiController::class, 'attendance']);
|
||||
Route::get('{studentId}/incidents', [StudentApiController::class, 'incidents']);
|
||||
Route::get('{studentId}/scores', [StudentApiController::class, 'scores']);
|
||||
Route::get('{studentId}/notes', [StudentApiController::class, 'notes']);
|
||||
Route::get('{studentId}/parents', [StudentApiController::class, 'parents']);
|
||||
Route::get('{studentId}/emergency-contacts', [StudentApiController::class, 'emergencyContacts']);
|
||||
Route::post('{studentId}/emergency-contacts', [StudentApiController::class, 'addEmergencyContact']);
|
||||
Route::patch('{studentId}/emergency-contacts/{contactId}', [StudentApiController::class, 'updateEmergencyContact']);
|
||||
Route::post('{studentId}/rfid', [StudentApiController::class, 'updateRfid']);
|
||||
Route::post('{studentId}/photo', [StudentApiController::class, 'uploadPhoto']);
|
||||
Route::get('{studentId}/photo', [StudentApiController::class, 'photo']);
|
||||
Route::get('{studentId}/report-card', [ReportCardsController::class, 'studentReport']);
|
||||
Route::get('{studentId}/score-card', [StudentApiController::class, 'scoreCard']);
|
||||
});
|
||||
|
||||
@@ -720,34 +740,40 @@ Route::prefix('v1')->group(function () {
|
||||
|
||||
Route::prefix('projects')->group(function () {
|
||||
Route::get('/', [ProjectScoreController::class, 'index']);
|
||||
Route::get('by-year', [ProjectScoreController::class, 'bySchoolYear']);
|
||||
Route::post('/', [ProjectScoreController::class, 'update']);
|
||||
Route::post('columns', [ProjectScoreController::class, 'addColumn']);
|
||||
});
|
||||
|
||||
Route::prefix('quizzes')->group(function () {
|
||||
Route::get('/', [QuizScoreController::class, 'index']);
|
||||
Route::get('by-year', [QuizScoreController::class, 'bySchoolYear']);
|
||||
Route::post('/', [QuizScoreController::class, 'update']);
|
||||
Route::post('columns', [QuizScoreController::class, 'addColumn']);
|
||||
});
|
||||
|
||||
Route::prefix('homework')->group(function () {
|
||||
Route::get('/', [HomeworkScoreController::class, 'index']);
|
||||
Route::get('by-year', [HomeworkScoreController::class, 'bySchoolYear']);
|
||||
Route::post('/', [HomeworkScoreController::class, 'update']);
|
||||
Route::post('columns', [HomeworkScoreController::class, 'addColumn']);
|
||||
});
|
||||
|
||||
Route::prefix('midterm')->group(function () {
|
||||
Route::get('/', [MidtermScoreController::class, 'index']);
|
||||
Route::get('by-year', [MidtermScoreController::class, 'bySchoolYear']);
|
||||
Route::post('/', [MidtermScoreController::class, 'update']);
|
||||
});
|
||||
|
||||
Route::prefix('final')->group(function () {
|
||||
Route::get('/', [FinalScoreController::class, 'index']);
|
||||
Route::get('by-year', [FinalScoreController::class, 'bySchoolYear']);
|
||||
Route::post('/', [FinalScoreController::class, 'update']);
|
||||
});
|
||||
|
||||
Route::prefix('participation')->group(function () {
|
||||
Route::get('/', [ParticipationScoreController::class, 'index']);
|
||||
Route::get('by-year', [ParticipationScoreController::class, 'bySchoolYear']);
|
||||
Route::post('/', [ParticipationScoreController::class, 'update']);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user