Files
alrahma_sunday_school_api/app/Http/Controllers/Api/CompetitionWinners/CompetitionWinnersController.php
T
2026-06-11 11:46:12 -04:00

399 lines
12 KiB
PHP

<?php
namespace App\Http\Controllers\Api\CompetitionWinners;
use App\Http\Controllers\Api\Core\BaseApiController;
use App\Http\Requests\Admin\SaveCompetitionScoresRequest;
use App\Http\Requests\Admin\StoreCompetitionWinnerRequest;
use App\Http\Requests\Admin\UpdateCompetitionWinnerRequest;
use App\Services\Admin\CompetitionWinners\CompetitionWinnersAdminService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CompetitionWinnersController extends BaseApiController
{
public function __construct(
private CompetitionWinnersAdminService $service,
) {
parent::__construct();
}
public function index(): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
$payload = $this->service->indexData();
return response()->json([
'ok' => true,
'competitions' => array_values(array_map(
fn ($row) => $this->normalizeCompetitionRow($this->rowToArray($row)),
$this->iterableToArray($payload['competitions'] ?? [])
)),
'sectionMap' => $payload['sectionMap'] ?? [],
]);
}
public function createForm(): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
return response()->json([
'ok' => true,
...$this->service->createFormData(),
]);
}
public function settingsForm(int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
$payload = $this->service->settingsFormData($id);
if ($payload === null) {
return response()->json([
'ok' => false,
'message' => 'Competition not found.',
], Response::HTTP_NOT_FOUND);
}
return response()->json([
'ok' => true,
...$payload,
]);
}
public function store(StoreCompetitionWinnerRequest $request): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
$validated = $request->validated();
$id = $this->service->storeCompetition(
$validated,
(array) ($validated['winner_overrides'] ?? []),
(array) ($validated['question_counts'] ?? []),
(array) ($validated['prizes'] ?? []),
$guard
);
return response()->json([
'ok' => true,
'message' => 'Competition created.',
'id' => $id,
], Response::HTTP_CREATED);
}
public function update(UpdateCompetitionWinnerRequest $request, int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
$validated = $request->validated();
$updated = $this->service->updateCompetition(
$id,
$validated,
(array) ($validated['winner_overrides'] ?? []),
(array) ($validated['question_counts'] ?? []),
(array) ($validated['prizes'] ?? [])
);
if (! $updated) {
return response()->json([
'ok' => false,
'message' => 'Competition not found.',
], Response::HTTP_NOT_FOUND);
}
return response()->json([
'ok' => true,
'message' => 'Competition updated.',
'id' => $id,
]);
}
public function scores(Request $request, int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
$payload = $this->service->editScoresData($id, $this->intOrNull($request->query('class_section_id')));
if ($payload === null) {
return response()->json([
'ok' => false,
'message' => 'Competition not found.',
], Response::HTTP_NOT_FOUND);
}
return response()->json([
'ok' => true,
...$payload,
]);
}
public function saveScores(SaveCompetitionScoresRequest $request, int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
$competition = $this->service->editScoresData($id, $this->intOrNull($request->input('class_section_id')));
if ($competition === null) {
return response()->json([
'ok' => false,
'message' => 'Competition not found.',
], Response::HTTP_NOT_FOUND);
}
$payload = $request->validated();
$saved = $this->service->saveScores(
$id,
(array) ($payload['scores'] ?? []),
$this->intOrNull($payload['class_section_id'] ?? null),
(array) ($competition['competition'] ?? [])
);
if (! $saved) {
return response()->json([
'ok' => false,
'message' => 'Select a class section before saving scores.',
], Response::HTTP_UNPROCESSABLE_ENTITY);
}
return response()->json([
'ok' => true,
'message' => 'Scores saved.',
'savedCount' => count((array) ($payload['scores'] ?? [])),
]);
}
public function preview(int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
$payload = $this->service->previewData($id);
if ($payload === null) {
return response()->json([
'ok' => false,
'message' => 'Competition not found.',
], Response::HTTP_NOT_FOUND);
}
return response()->json([
'ok' => true,
...$payload,
]);
}
public function winners(int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
$payload = $this->service->settingsFormData($id);
if ($payload === null || ! isset($payload['competition'])) {
return response()->json([
'ok' => false,
'message' => 'Competition not found.',
], Response::HTTP_NOT_FOUND);
}
return response()->json([
'ok' => true,
'competition' => $payload['competition'],
'rows' => $this->service->winnersListingRows($id),
'sectionMap' => $this->service->getClassSectionMap(),
]);
}
public function publish(int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
if (! $this->service->publishWinners($id)) {
return response()->json([
'ok' => false,
'message' => 'Competition not found.',
], Response::HTTP_NOT_FOUND);
}
return response()->json([
'ok' => true,
'message' => 'Competition winners published.',
]);
}
public function lock(int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
if (! $this->service->lockCompetition($id, $guard)) {
return response()->json([
'ok' => false,
'message' => 'Competition not found.',
], Response::HTTP_NOT_FOUND);
}
return response()->json([
'ok' => true,
'message' => 'Competition locked.',
]);
}
public function unlock(int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
if (! $this->service->unlockCompetition($id)) {
return response()->json([
'ok' => false,
'message' => 'Competition not found.',
], Response::HTTP_NOT_FOUND);
}
return response()->json([
'ok' => true,
'message' => 'Competition unlocked.',
]);
}
public function exportQuiz(Request $request, int $id): JsonResponse
{
$guard = $this->authenticatedAdminOrForbidden();
if ($guard instanceof JsonResponse) {
return $guard;
}
$validated = $request->validate([
'class_section_id' => ['nullable', 'integer'],
'semester' => ['nullable', 'string'],
'school_year' => ['nullable', 'string'],
]);
$schoolId = $this->intOrNull(optional(auth()->user())->school_id);
$result = $this->service->exportCompetitionToQuiz(
$id,
$this->intOrNull($validated['class_section_id'] ?? null) ?? 0,
$schoolId,
$guard,
$validated['semester'] ?? null,
$validated['school_year'] ?? null
);
return response()->json($result, $result['ok'] ? Response::HTTP_OK : Response::HTTP_UNPROCESSABLE_ENTITY);
}
private function authenticatedAdminOrForbidden(): int|JsonResponse
{
$user = $this->getCurrentUser();
if (! $user || (int) ($user->id ?? 0) <= 0) {
return response()->json(['ok' => false, 'message' => 'Unauthorized.'], Response::HTTP_UNAUTHORIZED);
}
$roles = array_map('strtolower', (array) ($user->roles ?? []));
$allowed = ['administrator', 'admin', 'principal', 'vice_principal', 'vice-principal'];
if (empty(array_intersect($roles, $allowed))) {
return response()->json(['ok' => false, 'message' => 'Forbidden.'], Response::HTTP_FORBIDDEN);
}
return (int) $user->id;
}
/**
* @param iterable<mixed> $rows
* @return array<int, mixed>
*/
private function iterableToArray(iterable $rows): array
{
return is_array($rows) ? $rows : iterator_to_array($rows, false);
}
/**
* @param array<string, mixed> $row
* @return array<string, mixed>
*/
private function normalizeCompetitionRow(array $row): array
{
$id = $this->intOrNull($row['id'] ?? $row['competition_id'] ?? null);
if ($id !== null) {
$row['id'] = $id;
}
$classSectionId = $this->intOrNull($row['class_section_id'] ?? null);
$row['class_section_id'] = $classSectionId;
$row['is_locked'] = (bool) ($row['is_locked'] ?? false);
$row['is_published'] = (bool) ($row['is_published'] ?? false);
return $row;
}
/**
* @return array<string, mixed>
*/
private function rowToArray(mixed $row): array
{
if (is_array($row)) {
return $row;
}
if ($row instanceof \JsonSerializable) {
$serialized = $row->jsonSerialize();
if (is_array($serialized)) {
return $serialized;
}
}
if (is_object($row) && method_exists($row, 'toArray')) {
$array = $row->toArray();
if (is_array($array)) {
return $array;
}
}
return (array) $row;
}
private function intOrNull(mixed $value): ?int
{
if ($value === null || $value === '') {
return null;
}
if (is_numeric($value)) {
return (int) $value;
}
return null;
}
}