Files
alrahma_sunday_school_api/app/Http/Controllers/Api/Parents/ParentPromotionController.php
T
2026-06-04 02:24:41 -04:00

174 lines
5.7 KiB
PHP

<?php
namespace App\Http\Controllers\Api\Parents;
use App\Http\Controllers\Api\Core\BaseApiController;
use App\Http\Requests\Promotions\ParentEnrollmentStepRequest;
use App\Http\Requests\Promotions\ParentPromotionOverviewRequest;
use App\Http\Resources\Promotions\StudentPromotionResource;
use App\Models\Student;
use App\Models\StudentPromotionRecord;
use App\Services\Promotions\PromotionEnrollmentService;
use App\Services\Promotions\PromotionQueryService;
use Illuminate\Http\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
/**
* Parent portal endpoints for the promotion + enrollment workflow
* (plan section 12). The parent sees the promoted level and can step
* through the enrollment checklist defined in plan section 8.
*/
class ParentPromotionController extends BaseApiController
{
public function __construct(
private PromotionEnrollmentService $service,
private PromotionQueryService $query
) {
parent::__construct();
}
public function overview(ParentPromotionOverviewRequest $request): JsonResponse
{
$guard = $this->parentIdOrUnauthorized();
if ($guard instanceof JsonResponse) {
return $guard;
}
$data = $this->service->overviewForParent(
$guard,
$request->validated()['next_school_year'] ?? null
);
return response()->json([
'ok' => true,
'records' => $data['records'],
'next_school_year' => $data['next_school_year'],
'message' => $data['message'],
]);
}
public function show(int $promotionId): JsonResponse
{
$guard = $this->parentIdOrUnauthorized();
if ($guard instanceof JsonResponse) {
return $guard;
}
$record = $this->loadOwnedRecord($promotionId, $guard);
if ($record instanceof JsonResponse) {
return $record;
}
return response()->json([
'ok' => true,
'data' => new StudentPromotionResource($this->query->detail($record)),
]);
}
public function start(int $promotionId): JsonResponse
{
$guard = $this->parentIdOrUnauthorized();
if ($guard instanceof JsonResponse) {
return $guard;
}
$record = $this->loadOwnedRecord($promotionId, $guard);
if ($record instanceof JsonResponse) {
return $record;
}
try {
$updated = $this->service->startEnrollment($record, $guard, $guard);
} catch (\RuntimeException $e) {
return response()->json(['ok' => false, 'message' => $e->getMessage()], Response::HTTP_CONFLICT);
}
return response()->json([
'ok' => true,
'data' => new StudentPromotionResource($this->query->detail($updated->refresh())),
]);
}
public function updateSteps(ParentEnrollmentStepRequest $request, int $promotionId): JsonResponse
{
$guard = $this->parentIdOrUnauthorized();
if ($guard instanceof JsonResponse) {
return $guard;
}
$record = $this->loadOwnedRecord($promotionId, $guard);
if ($record instanceof JsonResponse) {
return $record;
}
try {
$updated = $this->service->updateSteps($record, $guard, $request->steps(), $guard);
} catch (\RuntimeException $e) {
return response()->json(['ok' => false, 'message' => $e->getMessage()], Response::HTTP_CONFLICT);
}
return response()->json([
'ok' => true,
'data' => new StudentPromotionResource($this->query->detail($updated->refresh())),
]);
}
public function submit(int $promotionId): JsonResponse
{
$guard = $this->parentIdOrUnauthorized();
if ($guard instanceof JsonResponse) {
return $guard;
}
$record = $this->loadOwnedRecord($promotionId, $guard);
if ($record instanceof JsonResponse) {
return $record;
}
try {
$updated = $this->service->submitEnrollment($record, $guard, $guard);
} catch (\RuntimeException $e) {
return response()->json(['ok' => false, 'message' => $e->getMessage()], Response::HTTP_CONFLICT);
}
return response()->json([
'ok' => true,
'data' => new StudentPromotionResource($this->query->detail($updated->refresh())),
]);
}
private function loadOwnedRecord(int $promotionId, int $parentId): StudentPromotionRecord|JsonResponse
{
$record = StudentPromotionRecord::query()->find($promotionId);
if (!$record) {
return response()->json(['ok' => false, 'message' => 'Promotion record not found.'], Response::HTTP_NOT_FOUND);
}
$owns = (int) $record->parent_id === $parentId;
if (!$owns) {
$studentParentId = (int) (Student::query()
->where('id', $record->student_id)
->value('parent_id') ?? 0);
$owns = $studentParentId === $parentId;
}
if (!$owns) {
return response()->json(['ok' => false, 'message' => 'You are not authorised to view this promotion record.'], Response::HTTP_FORBIDDEN);
}
return $record;
}
private function parentIdOrUnauthorized(): int|JsonResponse
{
$request = request();
$primary = (int) ($request?->attributes?->get('primary_parent_id') ?? 0);
if ($primary > 0) {
return $primary;
}
$parentId = (int) (auth()->id() ?? 0);
if ($parentId <= 0) {
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], Response::HTTP_UNAUTHORIZED);
}
return $parentId;
}
}