Verified every finding against the code, then fixed correctness (redirects, advancement reset, duplicate heats, high-jump attempt entry, placement ranking with tie handling, delete-dependency 500s), security (secrets out of config, config-driven admin seed, login lockout, role authorization with school scoping, heat-time IDOR, forwarded headers, last-admin guards), schema integrity (nullable+filtered ExistingStudentId, unique indexes for rounds/heats/bar heights via SchemaIntegrityFixes migration), performance (N+1 removal in high jump/reports/standings/dashboard, SQL-side student paging), and hygiene (duplicate notifications, auto-dismiss scope, local bootstrap-icons, orphaned files, test-data.sql tournament creation). FluentValidation is now registered; AutoMapper bumped to 14.0.0 (advisory fully patched only in licence-changed 15.1.1 — documented). 11 new tests; 63/63 passing. Credential rotation and deploy-time DB_CONNECTION_STRING are required manual follow-ups, documented in bug-fixes.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
74 lines
3.0 KiB
Plaintext
74 lines
3.0 KiB
Plaintext
@model IEnumerable<EventRegistrationDto>
|
|
@{
|
|
ViewData["Title"] = "Field Event Scoring";
|
|
var telId = ViewBag.TournamentEventLevelId as int?;
|
|
var eventName = ViewBag.EventName as string;
|
|
var levelName = ViewBag.LevelName as string;
|
|
}
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<div>
|
|
<h2>Field Event Scoring</h2>
|
|
<p class="text-muted">@eventName - @levelName</p>
|
|
</div>
|
|
<div class="d-flex gap-2">
|
|
<form asp-action="CalculateScores" method="post">
|
|
<input type="hidden" name="tournamentEventLevelId" value="@telId" />
|
|
<button type="submit" class="btn btn-warning">Calculate Points</button>
|
|
</form>
|
|
<form asp-action="CalculatePlacements" method="post">
|
|
<input type="hidden" name="tournamentEventLevelId" value="@telId" />
|
|
<button type="submit" class="btn btn-success">Calculate Placements</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<div class="card shadow-sm">
|
|
<div class="card-body p-0">
|
|
<table class="table table-hover mb-0">
|
|
<thead class="table-dark">
|
|
<tr>
|
|
<th>#</th>
|
|
<th>Student</th>
|
|
<th>School</th>
|
|
<th>Performance</th>
|
|
<th>Points</th>
|
|
<th>Placement</th>
|
|
<th>Pts</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@{ int idx = 1; }
|
|
@foreach (var r in Model.OrderBy(r => r.Score?.Placement ?? int.MaxValue))
|
|
{
|
|
<tr>
|
|
<td>@idx</td>
|
|
<td>@r.StudentName</td>
|
|
<td>@r.SchoolName</td>
|
|
<td>
|
|
<form asp-action="RecordScore" method="post" class="d-flex gap-1">
|
|
<input type="hidden" name="tournamentEventLevelId" value="@telId" />
|
|
<input type="hidden" name="EventRegistrationId" value="@r.EventRegistrationId" />
|
|
<input type="number" step="0.01" name="RawPerformance" value="@r.Score?.RawPerformance" class="form-control form-control-sm" style="width:100px" />
|
|
<button type="submit" class="btn btn-sm btn-outline-primary">Save</button>
|
|
</form>
|
|
</td>
|
|
<td>@(r.Score?.CalculatedPoints ?? 0)</td>
|
|
<td>
|
|
@if (r.Score?.Placement != null)
|
|
{
|
|
<span class="badge bg-warning text-dark">#@r.Score.Placement</span>
|
|
}
|
|
</td>
|
|
<td>@(r.Score?.PlacementPoints ?? 0)</td>
|
|
<td></td>
|
|
</tr>
|
|
idx++;
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|