403 lines
12 KiB
PHP
403 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);
|
|
}
|
|
|
|
/**
|
|
* @return int|JsonResponse
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* @param mixed $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;
|
|
}
|
|
}
|