From cdc1082ae846925287d0333ac31b92d77c2f7266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zden=C4=9Bk=20Burda?= Date: Sat, 10 Jan 2026 13:19:44 +0100 Subject: [PATCH] =?UTF-8?q?Nezobrazovat=20detail=20logu=20anonymn=C3=ADmu?= =?UTF-8?q?=20u=C5=BEivateli=20#2=20-=20i=20v=20tabulce=20s=20deklarovan?= =?UTF-8?q?=C3=BDmi=20v=C3=BDsledky=20byl=20lok=C3=A1tor=20a=20ut=C3=ADkal?= =?UTF-8?q?y=20informace=20z=C3=A1vodn=C3=ADk=C5=AFm=20p=C5=99ed=20uz?= =?UTF-8?q?=C3=A1v=C4=9Brkou.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/LogResultController.php | 70 +++++++++++++- resources/js/components/ResultsTables.tsx | 96 ++++++++++++------- resources/js/pages/RoundDetailPage.tsx | 95 +++++++++++++----- .../Results/LogResultControllerTest.php | 86 +++++++++++++++++ 4 files changed, 287 insertions(+), 60 deletions(-) diff --git a/app/Http/Controllers/LogResultController.php b/app/Http/Controllers/LogResultController.php index 36c12c4..a6f5c55 100644 --- a/app/Http/Controllers/LogResultController.php +++ b/app/Http/Controllers/LogResultController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Models\LogResult; +use App\Models\Log; use App\Models\EvaluationRun; use App\Models\Round; use Illuminate\Http\Request; @@ -35,7 +36,7 @@ class LogResultController extends BaseController $query = LogResult::query() ->with([ 'evaluationRun.ruleSet:id,sixhr_ranking_mode', - 'log', + 'log.round', 'band:id,name,order', 'category:id,name,order', 'powerCategory:id,name,order', @@ -116,6 +117,16 @@ class LogResultController extends BaseController ->orderByDesc('official_score') ->paginate($perPage); + if ($this->shouldRedactDeclaredResults($request)) { + $items->getCollection()->transform(function (LogResult $item) { + if ($item->log) { + $item->log->pwwlo = null; + $item->log->codxc = null; + } + return $item; + }); + } + return response()->json($items); } @@ -149,12 +160,20 @@ class LogResultController extends BaseController { $logResult->load([ 'evaluationRun.ruleSet:id,sixhr_ranking_mode', - 'log', + 'log.round', 'band:id,name,order', 'category:id,name,order', 'powerCategory:id,name,order', ]); + $request = request(); + if ($this->shouldRedactDeclaredResults($request, $logResult)) { + if ($logResult->log) { + $logResult->log->pwwlo = null; + $logResult->log->codxc = null; + } + } + return response()->json($logResult); } @@ -236,4 +255,51 @@ class LogResultController extends BaseController 'status_reason' => ['sometimes', 'nullable', 'string'], ]); } + + private function shouldRedactDeclaredResults(Request $request, ?LogResult $logResult = null): bool + { + $user = $request->user(); + if ($user && $user->is_admin) { + return false; + } + + if ($logResult) { + $run = $logResult->evaluationRun; + $isClaimed = $run && strtoupper((string) $run->rules_version) === 'CLAIMED'; + if (! $isClaimed) { + return false; + } + return ! $this->hasOfficialResultsPublished($logResult->log?->round); + } + + if ($request->get('status') !== 'CLAIMED') { + return false; + } + + $round = null; + if ($request->filled('round_id')) { + $round = Round::find((int) $request->get('round_id')); + } elseif ($request->filled('evaluation_run_id')) { + $run = EvaluationRun::find((int) $request->get('evaluation_run_id')); + $round = $run?->round; + } elseif ($request->filled('log_id')) { + $log = Log::with('round')->find((int) $request->get('log_id')); + $round = $log?->round; + } + + return ! $this->hasOfficialResultsPublished($round); + } + + private function hasOfficialResultsPublished(?Round $round): bool + { + if (! $round || ! $round->official_evaluation_run_id) { + return false; + } + + return EvaluationRun::query() + ->where('id', $round->official_evaluation_run_id) + ->where('status', 'SUCCEEDED') + ->where('result_type', 'FINAL') + ->exists(); + } } diff --git a/resources/js/components/ResultsTables.tsx b/resources/js/components/ResultsTables.tsx index 6cf5840..442db59 100644 --- a/resources/js/components/ResultsTables.tsx +++ b/resources/js/components/ResultsTables.tsx @@ -58,6 +58,8 @@ type ResultsTablesProps = { onResultTypeChange?: (label: string | null, className: string, resultType: string | null) => void; refreshKey?: string | number | null; evaluationRunId?: number | null; + isFinalPublished?: boolean; + isAdmin?: boolean; }; @@ -70,6 +72,8 @@ export default function ResultsTables({ onResultTypeChange, refreshKey = null, evaluationRunId = null, + isFinalPublished = false, + isAdmin = false, }: ResultsTablesProps) { const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); @@ -86,6 +90,8 @@ export default function ResultsTables({ const { t } = useTranslation(); const navigate = useNavigate(); const location = useLocation(); + const showScoreTotal = mode === "final"; + const showLocatorOdx = mode === "final" || isAdmin || isFinalPublished; useEffect(() => { if (!roundId) return; @@ -251,12 +257,16 @@ export default function ResultsTables({ const headerColumns = [ {t("results_table_rank") ?? "Pořadí"}, {t("results_table_callsign") ?? "Značka v závodě"}, - {t("results_table_locator") ?? "Lokátor"}, + showLocatorOdx + ? {t("results_table_locator") ?? "Lokátor"} + : null, {t("results_table_category") ?? "Kategorie"}, {t("results_table_band") ?? "Pásmo"}, {t("results_table_power_watt") ?? "Výkon [W]"}, {t("results_table_power_category") ?? "Výkonová kat."}, - {t("results_table_score_total") ?? "Body celkem"}, + showScoreTotal + ? {t("results_table_score_total") ?? "Body celkem"} + : null, {t("results_table_claimed_score") ?? "Deklarované body"}, {t("results_table_qso_count") ?? "Počet QSO"}, showCalculatedColumns @@ -275,7 +285,9 @@ export default function ResultsTables({ ? {t("results_table_unique_qso") ?? "Unique QSO"} : null, {t("results_table_score_per_qso") ?? "Body / QSO"}, - {t("results_table_odx") ?? "ODX"}, + showLocatorOdx + ? {t("results_table_odx") ?? "ODX"} + : null, {t("results_table_antenna") ?? "Anténa"}, {t("results_table_antenna_height") ?? "Ant. height"}, showCalculatedColumns @@ -293,7 +305,7 @@ export default function ResultsTables({ {heading}