furhter updates to display when an admin invalidated a run instead of hiding it

This commit is contained in:
jenz
2026-09-30 15:32:22 +02:00
parent a3765a73d9
commit 54827b01ba
18 changed files with 364 additions and 44 deletions
+13 -4
View File
@@ -28,8 +28,8 @@ Points are calculated per category, from each player's **best valid** time only.
| Base points | n − (position − 1): the fastest gets n (the number of completions), each position below gets one less. The slower half gets 0, so on big boards points drop from about n/2 straight to 0 at the cut. |
| Bonus multiplier | Only on boards with 100+ completions. 4× at #1, sliding smoothly to 2× at the top-1% mark, then to 1× at the top-5% mark. |
| CLASSIC RACETIMER | Final points ÷ 10. |
| Invalid category | Still shown with positions, but gives 0 points. |
| Invalid record | Listed separately under `invalidated` with no position and 0 points. Only that one run is removed; the player's previous valid time counts again. |
| Invalid category | Still shown with positions, but gives 0 points. The admin and time are public (`invalidation`). |
| Invalid record | Still listed on the board in time order with `isInvalid: true`, position 0 and 0 points. Only that one run is removed from the ranking; the player's previous valid time counts again. The admin and time are public (`invalidation`). |
| Servers | ZE1 and ZE2 points and ranks are separate. Categories from any other tag (e.g. `dev`) are hidden. |
The old flat +2500 bonus for small boards is gone.
@@ -42,6 +42,15 @@ The old flat +2500 bonus for small boards is gone.
Without `?server=`, both endpoints use `defaultServerTag` (ze1). On ZE2, add `?server=ze2` to those two URLs so levels come from ZE2 points.
Levels drop for CLASSIC data, as intended.
## Who invalidated what
Run `racetimer_invalidation_audit.sql` once on the racetimer database. It adds `invalidated_by_steam`, `invalidated_by_name` and `invalidated_at` to `timer_records` and `zone_categories`.
- Invalidating stores the signed-in admin's SteamID, name and the current time. Invalidating something that is already invalid keeps the first admin and time.
- Restoring sets `is_invalid = 0` and clears the three columns.
- Every invalid run and category in the API has `invalidation: {steamID, steamID64, name, at}` (`at` in Unix seconds). Player rows and history also have `categoryInvalidation`. Rows flagged before the columns existed have all fields `null`.
- Until the script is run, the site keeps working (a warning is logged) but cannot say who invalidated what, and the admin buttons return an error asking for the script.
## Endpoints
`{steamid}` accepts `STEAM_0:x:y`, `STEAM_1:x:y`, `[U:1:n]` or a SteamID64.
@@ -56,11 +65,11 @@ Errors are JSON: `{"statusCode": 404, "errorMessage": "..."}`.
| `GET timers/leaderboard/minified/{offset}?server=` | `[{name, PlayerPoints}]` (for `toplvl.sp`) |
| `GET timers/player/{steamid}?server=` | One player, same fields as the leaderboard. 404 if unknown. |
| `GET timers/player/badges/{steamid}` | `{badgesUrls, badges: [{name, url}]}` |
| `GET timers/player/maps/{steamid}/{offset}?server=` | 50 rows of the player's best per category. Fields: `recordId`, `categoryId`, `mapName`, `stage`, `categoryNumber`, `serverTag`, `isLegacy`, `categoryInvalid`, `time`, `position`, `completions`, `bonusMultiplier`, `points`, `recordedAt`. Without `server`, both servers are included. |
| `GET timers/player/maps/{steamid}/{offset}?server=` | 50 rows of the player's best per category, plus any faster invalidated run (`isInvalid: true`, position 0). Fields: `recordId`, `categoryId`, `mapName`, `stage`, `categoryNumber`, `serverTag`, `isLegacy`, `categoryInvalid`, `isInvalid`, `time`, `position`, `completions`, `bonusMultiplier`, `points`, `recordedAt`. Without `server`, both servers are included. |
| `GET timers/player/history/{steamid}/{offset}?categoryId=` | 50 improvements, newest first. Fields: `time`, `previousTime`, `improvedBy` (seconds), `recordedAt`, `isInvalid`, `isCurrentBest`, plus the category fields. Legacy records are last, with `recordedAt: null`. |
| `GET timers/allmaps` | `[{mapName, allCategoriesInvalid, stages: [{stage, allCategoriesInvalid, categories: [category]}]}]` |
| `GET timers/map/{mapname}` | One map in the same shape (case-insensitive). |
| `GET timers/category/{id}/{offset}` | `{category, offset, pageSize, entries: [75], invalidated: [...]}` |
| `GET timers/category/{id}/{offset}` | `{category, offset, pageSize, entries: [75], invalidated: [...]}`. `entries` holds valid times and invalidated runs together, fastest first; invalidated ones have `isInvalid: true`, `position: 0`, `points: 0`. `invalidated` repeats just those runs. |
| `GET timers/searchplayers/{text}?server=` | Up to 100 players, matched on name or Steam ID. |
| `GET timers/searchmaps/{text}` | Maps whose name contains the text. |