240 lines
8.5 KiB
PHP
240 lines
8.5 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers;
|
||
|
||
use App\Models\LogResult;
|
||
use App\Models\EvaluationRun;
|
||
use App\Models\Round;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Http\JsonResponse;
|
||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||
use Illuminate\Routing\Controller as BaseController;
|
||
use Illuminate\Support\Str;
|
||
|
||
class LogResultController extends BaseController
|
||
{
|
||
use AuthorizesRequests, ValidatesRequests;
|
||
|
||
public function __construct()
|
||
{
|
||
// zápisové operace jen pro přihlášené
|
||
$this->middleware('auth:sanctum')->only(['store', 'update', 'destroy']);
|
||
}
|
||
|
||
/**
|
||
* Seznam výsledků logů – filtrování podle evaluation_run_id,
|
||
* log_id, band_id, category_id, status.
|
||
*/
|
||
public function index(Request $request): JsonResponse
|
||
{
|
||
$perPage = (int) $request->get('per_page', 100);
|
||
$statusParam = $request->get('status');
|
||
$isClaimedRequest = $statusParam === 'CLAIMED';
|
||
|
||
$query = LogResult::query()
|
||
->with([
|
||
'evaluationRun.ruleSet:id,sixhr_ranking_mode',
|
||
'log',
|
||
'band:id,name,order',
|
||
'category:id,name,order',
|
||
'powerCategory:id,name,order',
|
||
]);
|
||
|
||
if ($request->filled('evaluation_run_id')) {
|
||
$query->where('evaluation_run_id', (int) $request->get('evaluation_run_id'));
|
||
}
|
||
|
||
if ($request->filled('round_id')) {
|
||
$roundId = (int) $request->get('round_id');
|
||
$query->whereHas('log', function ($q) use ($roundId) {
|
||
$q->where('round_id', $roundId);
|
||
});
|
||
if (! $request->filled('evaluation_run_id') && $request->filled('result_type')) {
|
||
$round = Round::find($roundId);
|
||
$resultType = strtoupper((string) $request->get('result_type'));
|
||
$selectedRunId = null;
|
||
if ($round) {
|
||
if ($resultType === 'FINAL') {
|
||
$selectedRunId = $round->official_evaluation_run_id;
|
||
} elseif ($resultType === 'PRELIMINARY') {
|
||
$selectedRunId = $round->preliminary_evaluation_run_id;
|
||
} elseif ($resultType === 'TEST') {
|
||
$selectedRunId = $round->test_evaluation_run_id;
|
||
} elseif ($resultType === 'AUTO') {
|
||
$selectedRunId = $round->official_evaluation_run_id
|
||
?? $round->preliminary_evaluation_run_id;
|
||
}
|
||
}
|
||
if ($selectedRunId) {
|
||
$query->where('evaluation_run_id', $selectedRunId);
|
||
} else {
|
||
$query->whereRaw('1=0');
|
||
}
|
||
}
|
||
if (! $request->filled('evaluation_run_id') && $isClaimedRequest) {
|
||
$latestClaimedRunId = EvaluationRun::where('round_id', $roundId)
|
||
->where('rules_version', 'CLAIMED')
|
||
->orderByDesc('id')
|
||
->value('id');
|
||
if ($latestClaimedRunId) {
|
||
$query->where('evaluation_run_id', $latestClaimedRunId);
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($request->filled('log_id')) {
|
||
$query->where('log_id', (int) $request->get('log_id'));
|
||
}
|
||
|
||
if ($request->filled('band_id')) {
|
||
$query->where('band_id', (int) $request->get('band_id'));
|
||
}
|
||
|
||
if ($request->filled('category_id')) {
|
||
$query->where('category_id', (int) $request->get('category_id'));
|
||
}
|
||
|
||
if ($request->filled('status') && ! $isClaimedRequest) {
|
||
$query->where('status', $statusParam);
|
||
}
|
||
|
||
if ($request->boolean('only_ok', false)) {
|
||
$pcallExpr = "UPPER(REPLACE(TRIM(pcall), ' ', ''))";
|
||
$query->whereHas('log', function ($q) use ($pcallExpr) {
|
||
$q->where(function ($sub) use ($pcallExpr) {
|
||
$sub->whereRaw("{$pcallExpr} LIKE ?", ['OK%'])
|
||
->orWhereRaw("{$pcallExpr} LIKE ?", ['OL%'])
|
||
->orWhereRaw("{$pcallExpr} LIKE ?", ['%/OK%'])
|
||
->orWhereRaw("{$pcallExpr} LIKE ?", ['%/OL%']);
|
||
});
|
||
});
|
||
}
|
||
|
||
// implicitně řadit podle oficiálního skóre
|
||
$items = $query
|
||
->orderByDesc('official_score')
|
||
->paginate($perPage);
|
||
|
||
return response()->json($items);
|
||
}
|
||
|
||
/**
|
||
* Vytvoření záznamu výsledku logu.
|
||
* Typicky voláno vyhodnocovačem, ne přímo z UI.
|
||
*/
|
||
public function store(Request $request): JsonResponse
|
||
{
|
||
$this->authorize('create', LogResult::class);
|
||
|
||
$data = $this->validateData($request);
|
||
|
||
$result = LogResult::create($data);
|
||
|
||
$result->load([
|
||
'evaluationRun.ruleSet:id,sixhr_ranking_mode',
|
||
'log',
|
||
'band:id,name,order',
|
||
'category:id,name,order',
|
||
'powerCategory:id,name,order',
|
||
]);
|
||
|
||
return response()->json($result, 201);
|
||
}
|
||
|
||
/**
|
||
* Detail jednoho výsledku.
|
||
*/
|
||
public function show(LogResult $logResult): JsonResponse
|
||
{
|
||
$logResult->load([
|
||
'evaluationRun.ruleSet:id,sixhr_ranking_mode',
|
||
'log',
|
||
'band:id,name,order',
|
||
'category:id,name,order',
|
||
'powerCategory:id,name,order',
|
||
]);
|
||
|
||
return response()->json($logResult);
|
||
}
|
||
|
||
/**
|
||
* Aktualizace výsledku (partial).
|
||
* Typicky pro ruční korekci statutu / poznámky.
|
||
*/
|
||
public function update(Request $request, LogResult $logResult): JsonResponse
|
||
{
|
||
$this->authorize('update', $logResult);
|
||
|
||
$data = $this->validateData($request, partial: true);
|
||
|
||
$logResult->fill($data);
|
||
$logResult->save();
|
||
|
||
$logResult->load([
|
||
'evaluationRun.ruleSet:id,sixhr_ranking_mode',
|
||
'log',
|
||
'band:id,name,order',
|
||
'category:id,name,order',
|
||
'powerCategory:id,name,order',
|
||
]);
|
||
|
||
return response()->json($logResult);
|
||
}
|
||
|
||
/**
|
||
* Smazání výsledku.
|
||
*/
|
||
public function destroy(LogResult $logResult): JsonResponse
|
||
{
|
||
$this->authorize('delete', $logResult);
|
||
|
||
$logResult->delete();
|
||
|
||
return response()->json(null, 204);
|
||
}
|
||
|
||
/**
|
||
* Validace pro store / update.
|
||
*/
|
||
protected function validateData(Request $request, bool $partial = false): array
|
||
{
|
||
$required = $partial ? 'sometimes' : 'required';
|
||
|
||
return $request->validate([
|
||
'evaluation_run_id' => [$required, 'integer', 'exists:evaluation_runs,id'],
|
||
'log_id' => [$required, 'integer', 'exists:logs,id'],
|
||
|
||
'band_id' => ['sometimes', 'nullable', 'integer', 'exists:bands,id'],
|
||
'category_id' => ['sometimes', 'nullable', 'integer', 'exists:categories,id'],
|
||
'power_category_id' => ['sometimes', 'nullable', 'integer', 'exists:power_categories,id'],
|
||
|
||
'claimed_qso_count' => ['sometimes', 'nullable', 'integer', 'min:0'],
|
||
'claimed_score' => ['sometimes', 'nullable', 'integer', 'min:0'],
|
||
|
||
'valid_qso_count' => ['sometimes', 'integer', 'min:0'],
|
||
'dupe_qso_count' => ['sometimes', 'integer', 'min:0'],
|
||
'busted_qso_count' => ['sometimes', 'integer', 'min:0'],
|
||
'other_error_qso_count' => ['sometimes', 'integer', 'min:0'],
|
||
'total_qso_count' => ['sometimes', 'integer', 'min:0'],
|
||
'discarded_qso_count' => ['sometimes', 'integer', 'min:0'],
|
||
'discarded_points' => ['sometimes', 'integer'],
|
||
'discarded_qso_percent' => ['sometimes', 'numeric', 'min:0'],
|
||
'unique_qso_count' => ['sometimes', 'integer', 'min:0'],
|
||
|
||
'official_score' => ['sometimes', 'integer'],
|
||
'penalty_score' => ['sometimes', 'integer'],
|
||
'base_score' => ['sometimes', 'integer'],
|
||
'multiplier_count' => ['sometimes', 'integer', 'min:0'],
|
||
'multiplier_score' => ['sometimes', 'integer'],
|
||
'score_per_qso' => ['sometimes', 'numeric', 'min:0'],
|
||
|
||
'rank_overall' => ['sometimes', 'nullable', 'integer', 'min:1'],
|
||
'rank_in_category' => ['sometimes', 'nullable', 'integer', 'min:1'],
|
||
|
||
'status' => ['sometimes', 'string', 'max:20'],
|
||
'status_reason' => ['sometimes', 'nullable', 'string'],
|
||
]);
|
||
}
|
||
}
|