Procházet zdrojové kódy

feat: refactor ClassController and ClassService for active unit handling; add franchisee classes routes

ebagabee před 1 týdnem
rodič
revize
f97271a728

+ 17 - 6
app/Http/Controllers/ClassController.php

@@ -30,26 +30,29 @@ public function index(): JsonResponse
 
     public function store(ClassRequest $request): JsonResponse
     {
-        $data = array_merge($request->validated(), ['unit_id' => $this->activeUnitId()]);
+        $unitId = $this->activeUnitId();
+        abort_unless($unitId, 403, 'Nenhuma unidade ativa foi selecionada.');
+
+        $data = array_merge($request->validated(), ['unit_id' => $unitId]);
         $item = $this->service->create($data);
         return $this->successResponse(payload: new ClassResource($item), message: __('messages.created'), code: 201);
     }
 
     public function show(int $id): JsonResponse
     {
-        $item = $this->service->findById($id);
+        $item = $this->service->findByIdForUnit($id, $this->requiredActiveUnitId());
         return $this->successResponse(payload: new ClassResource($item));
     }
 
     public function update(ClassRequest $request, int $id): JsonResponse
     {
-        $item = $this->service->update($id, $request->validated());
+        $item = $this->service->update($id, $this->requiredActiveUnitId(), $request->validated());
         return $this->successResponse(payload: new ClassResource($item), message: __('messages.updated'));
     }
 
     public function destroy(int $id): JsonResponse
     {
-        $this->service->delete($id);
+        $this->service->delete($id, $this->requiredActiveUnitId());
         return $this->successResponse(message: __('messages.deleted'), code: 204);
     }
 
@@ -58,7 +61,7 @@ public function destroy(int $id): JsonResponse
      */
     public function students(int $id): JsonResponse
     {
-        $students = $this->service->getStudentsForClass($id);
+        $students = $this->service->getStudentsForClass($id, $this->requiredActiveUnitId());
         return $this->successResponse(payload: $students);
     }
 
@@ -75,7 +78,15 @@ public function saveAttendance(Request $request, int $id): JsonResponse
             'attendances.*.notes'      => 'nullable|string',
         ]);
 
-        $this->service->saveAttendance($id, $validated['attendances']);
+        $this->service->saveAttendance($id, $this->requiredActiveUnitId(), $validated['attendances']);
         return $this->successResponse(message: __('messages.updated'));
     }
+
+    private function requiredActiveUnitId(): int
+    {
+        $unitId = $this->activeUnitId();
+        abort_unless($unitId, 403, 'Nenhuma unidade ativa foi selecionada.');
+
+        return $unitId;
+    }
 }

+ 7 - 1
app/Http/Requests/ClassRequest.php

@@ -3,6 +3,7 @@
 namespace App\Http\Requests;
 
 use Illuminate\Foundation\Http\FormRequest;
+use Illuminate\Validation\Rule;
 
 class ClassRequest extends FormRequest
 {
@@ -17,7 +18,12 @@ public function rules(): array
 
         return [
             'title'                 => "{$required}|string|max:255",
-            'class_package_unit_id' => "{$required}|integer|exists:class_package_units,id",
+            'class_package_unit_id' => [
+                $required,
+                'integer',
+                Rule::exists('class_package_units', 'id')
+                    ->where('unit_id', $this->input('active_unit_id')),
+            ],
             'instructor'            => 'nullable|string|max:255',
             'room'                  => 'nullable|string|max:255',
             'date_time_start'       => "{$required}|date",

+ 18 - 20
app/Services/ClassService.php

@@ -28,9 +28,11 @@ public function getAllByUnit(int $unitId): Collection
             });
     }
 
-    public function findById(int $id): ?SchoolClass
+    public function findByIdForUnit(int $id, int $unitId): SchoolClass
     {
-        return SchoolClass::with('packageUnit')->find($id);
+        return SchoolClass::with('packageUnit')
+            ->where('unit_id', $unitId)
+            ->findOrFail($id);
     }
 
     public function create(array $data): SchoolClass
@@ -38,25 +40,17 @@ public function create(array $data): SchoolClass
         return SchoolClass::create($data)->load('packageUnit');
     }
 
-    public function update(int $id, array $data): ?SchoolClass
+    public function update(int $id, int $unitId, array $data): SchoolClass
     {
-        $model = SchoolClass::find($id);
-
-        if (!$model) {
-            return null;
-        }
+        $model = $this->findByIdForUnit($id, $unitId);
 
         $model->update($data);
         return $model->fresh('packageUnit');
     }
 
-    public function delete(int $id): bool
+    public function delete(int $id, int $unitId): bool
     {
-        $model = SchoolClass::find($id);
-
-        if (!$model) {
-            return false;
-        }
+        $model = $this->findByIdForUnit($id, $unitId);
 
         return (bool) $model->delete();
     }
@@ -65,12 +59,9 @@ public function delete(int $id): bool
      * Lista os alunos com contrato ATIVO no pacote vinculado à aula,
      * já mesclando a presença registrada (se houver) para aquela aula.
      */
-    public function getStudentsForClass(int $classId): array
+    public function getStudentsForClass(int $classId, int $unitId): array
     {
-        $class = SchoolClass::find($classId);
-        if (!$class) {
-            return [];
-        }
+        $class = $this->findByIdForUnit($classId, $unitId);
 
         $students = $this->activeStudentsQuery($class->class_package_unit_id, $class->unit_id)
             ->orderBy('students.name')
@@ -108,8 +99,15 @@ public function getStudentsForClass(int $classId): array
      *
      * @param array<int, array{student_id:int, in_class:bool, justified?:bool, notes?:string|null}> $items
      */
-    public function saveAttendance(int $classId, array $items): void
+    public function saveAttendance(int $classId, int $unitId, array $items): void
     {
+        $class = $this->findByIdForUnit($classId, $unitId);
+        $allowedStudentIds = $this->activeStudentsQuery($class->class_package_unit_id, $unitId)
+            ->whereIn('students.id', collect($items)->pluck('student_id'))
+            ->pluck('students.id');
+
+        abort_unless($allowedStudentIds->count() === count($items), 422, 'A lista contém alunos que não pertencem a esta aula.');
+
         DB::transaction(function () use ($classId, $items) {
             foreach ($items as $item) {
                 $inClass   = (bool) ($item['in_class'] ?? false);

+ 0 - 15
routes/authRoutes/class.php

@@ -1,15 +0,0 @@
-<?php
-
-use Illuminate\Support\Facades\Route;
-use App\Http\Controllers\ClassController;
-
-Route::controller(ClassController::class)->prefix('class')->group(function () {
-    Route::post('/', 'store')->middleware('permission:class,add');
-
-    Route::get('/{id}', 'show')->middleware('permission:class,view');
-
-    // Lista de presença
-    Route::put('/{id}', 'update')->middleware('permission:class,edit');
-
-    Route::delete('/{id}', 'destroy')->middleware('permission:class,delete');
-});

+ 0 - 16
routes/authRoutes/class_attendance.php

@@ -1,16 +0,0 @@
-<?php
-
-use Illuminate\Support\Facades\Route;
-use App\Http\Controllers\ClassAttendanceController;
-
-Route::controller(ClassAttendanceController::class)->prefix('class-attendance')->group(function () {
-    Route::get('/', 'index')->middleware('permission:class-attendance,view');
-
-    Route::post('/', 'store')->middleware('permission:class-attendance,add');
-
-    Route::get('/{id}', 'show')->middleware('permission:class-attendance,view');
-
-    Route::put('/{id}', 'update')->middleware('permission:class-attendance,edit');
-
-    Route::delete('/{id}', 'destroy')->middleware('permission:class-attendance,delete');
-});

+ 15 - 0
routes/authRoutes/franchisee_classes.php

@@ -0,0 +1,15 @@
+<?php
+
+use App\Http\Controllers\ClassController;
+use Illuminate\Support\Facades\Route;
+
+Route::prefix('franchisee/classes')->group(function () {
+    Route::get('/', [ClassController::class, 'index'])->middleware('permission:franchisee_classes,view');
+    Route::post('/', [ClassController::class, 'store'])->middleware('permission:franchisee_classes,add');
+    Route::get('/{id}', [ClassController::class, 'show'])->whereNumber('id')->middleware('permission:franchisee_classes,view');
+    Route::put('/{id}', [ClassController::class, 'update'])->whereNumber('id')->middleware('permission:franchisee_classes,edit');
+    Route::delete('/{id}', [ClassController::class, 'destroy'])->whereNumber('id')->middleware('permission:franchisee_classes,delete');
+
+    Route::get('/{id}/students', [ClassController::class, 'students'])->whereNumber('id')->middleware('permission:franchisee_classes,view');
+    Route::post('/{id}/attendances', [ClassController::class, 'saveAttendance'])->whereNumber('id')->middleware('permission:franchisee_classes,edit');
+});

+ 1 - 1
routes/authRoutes/user.php

@@ -8,7 +8,7 @@
     Route::get('/current/auth', 'authUser');
     Route::put('/me', 'updateMe');
 
-    Route::get('/unit', 'indexByUnit')->middleware('permission:config.user,view');
+    Route::get('/unit', 'indexByUnit')->middleware('permission:franchisee_users,view');
     Route::get('/all/types', 'getUserTypes')
         ->middleware('permission:franchisor_registrations|config.user,view');
 });