Public Access
feat(library): add IGDB editions, game links and auditor queue
Tables game_edition (IGDB "same game" id per library key), game_link (global sets set by auditors), game_link_pair (queue of IGDB and requested pairs), game_link_request and account_name. Fetch IGDB editions, link and unlink with audit rows, serve the paged auditor queue with request counts. WireMock recordings for the editions query.
This commit is contained in:
1 parent
a12ed20705
commit
e806670d26
43 files changed
+1877
-22
No files matched your search
@@ -67,6 +67,10 @@ To Be Played is split into three repositories:
|
||||
backgrounds (V27 widens `reward_equipped.slot`); a `BUY` row proves ownership,
|
||||
`reward_equipped` holds what is worn. A platform admin owns every item (the role of the login token, or the `role`
|
||||
claim of the profile ticket for visitors).
|
||||
- **Editions and links**: editions, remasters and ports of one game stay separate library rows, but an AUDITOR can
|
||||
link their keys as one game for every user (see "Editions of one game"). IGDB suggests pairs, users can ask for
|
||||
one, and one queue holds both. Every link, unlink and dismissal goes to `admin_audit`
|
||||
(`GAME_LINK`, `GAME_UNLINK`, `GAME_LINK_DISMISS`).
|
||||
- **Wishlist**: synced from Steam with store price and discount.
|
||||
- **Broken image repair**: the frontend reports a Steam cover or achievement icon that does not load. At 01:30
|
||||
(Europe/Berlin) a job checks up to 200 reports. A cover that loads again is left alone; else the store's hashed
|
||||
@@ -131,6 +135,10 @@ ArchUnit role rules (`RoleAnnotationRules`) and `src/test/resources/contract/aut
|
||||
| `PATCH` | `/api/library/games/{appid}/backlog` (only the sent fields; `null` clears one) | JWT |
|
||||
| `PUT`, `DELETE` | `/api/library/games/{appid}/corrections/{field}` (`{value}`; `name`, `image`, `speedrun`, `moods`, `endless`, `genres`; `204`, `400 INVALID_CORRECTION`) | JWT, AUDITOR |
|
||||
| `POST` | `/api/library/games/{appid}/merge` (`{otherAppid}`; `200 {appid}` = the key that stays, `400 SAME_GAME` / `STEAM_GAMES`, `404 GAME_NOT_FOUND`) | JWT, AUDITOR |
|
||||
| `POST`, `DELETE` | `/api/library/games/{appid}/link` (POST `{otherAppid}`, `204`, `400 SAME_GAME`, `404 GAME_NOT_FOUND`, `409 ALREADY_LINKED`; DELETE takes the game out of its set, `204`, `404 NOT_LINKED`) | JWT, AUDITOR |
|
||||
| `GET` | `/api/library/link-queue?page=&size=` (`PageDto` of `{a, b, igdb, requests, createdAt}`: both games, most requested first; size 20, 40 or 80) | JWT, AUDITOR |
|
||||
| `DELETE` | `/api/library/link-queue/{appid}/{otherAppid}` (dismiss; `204`, `404 PAIR_NOT_OPEN`) | JWT, AUDITOR |
|
||||
| `POST` | `/api/library/games/{appid}/link-requests` (`{otherAppid}`, both in the caller's library; `204`, `400 SAME_GAME`, `404 GAME_NOT_FOUND`, `409 ALREADY_LINKED` / `PAIR_DISMISSED`, `429 TOO_MANY_REQUESTS`) | JWT |
|
||||
| `PUT` | `/api/library/games/{appid}/status` (status only, keeps rating, notes, priority) | JWT |
|
||||
| `PUT` | `/api/library/games/{appid}/finished-hint` (`{dismissed: ENDING\|PLAYTIME}`, "Not yet"; `204`) | JWT |
|
||||
| `PUT` | `/api/library/games/{appid}/hidden` (`{hidden}`; `409 MANUAL_GAME` for a game added by hand) | JWT |
|
||||
@@ -319,13 +327,30 @@ since the sync would bring both back. In one transaction:
|
||||
current status the user chose (both: the one chosen last); a gap is filled from the other row. Source, platform and playtime stay, unless the
|
||||
Steam copy is no longer owned. Both status histories stay; the merge itself logs no status change.
|
||||
- The shared rows of the old key (catalog row, moods, speedrun, time to beat, corrections, broken images) are
|
||||
deleted.
|
||||
deleted. So are its queue pairs, its requests and its `game_edition` row; its set row goes to the kept key (see
|
||||
"Editions of one game").
|
||||
- `game_alias` points the old key to the new one (kept flat), so a later add of the old IGDB game lands on the new
|
||||
key. `admin_audit` gets one `GAME_MERGE` row: who, both keys, both names and how many rows moved or were combined.
|
||||
|
||||
There is no undo. The game search shows games already in ToBePlayed first, with their catalog name and image, and
|
||||
games other users added by hand that IGDB did not return; `inCatalog` marks both (only those can be merged).
|
||||
|
||||
### Editions of one game
|
||||
|
||||
IGDB tells which library keys are one game: `game_edition` (V28) holds a "same game" key per library key, refreshed
|
||||
like `game_mood` (stale check, nightly sync, add, detail view; `app.library.edition-ttl-days`). The key is
|
||||
`version_parent` for an edition, else `parent_game` when `game_type` is 9 (remaster) or 11 (port), else the game's own
|
||||
IGDB id; remakes (8) keep their own id. `null` when IGDB does not know the game.
|
||||
|
||||
- `game_link(appid, set_id)`: the keys an auditor linked, for every user. A set is every row with one `set_id`.
|
||||
An unlink takes one key out; a set of one is dropped. A merge puts the kept key in the merged key's set; when both have a set, the sets join.
|
||||
- `game_link_pair` is the auditor queue (`OPEN`, `DISMISSED`, `LINKED`). IGDB pairs are inserted when the queue is
|
||||
read; a row in any state keeps the pair out for good. An unlink dismisses the pairs of that key with the former
|
||||
members. `game_link_request` holds who asked for a pair (the queue shows only the count). A user asks for a pair of
|
||||
two games of their own library; at most 20 open requests per user (a per-user advisory lock makes the cap hold for parallel calls), a dismissed pair answers `409 PAIR_DISMISSED`.
|
||||
- The game detail has `linked` and `editions` (the user's other listed games of the set); a game row has `editions`
|
||||
(size of the set in the user's library, `null` below 2).
|
||||
|
||||
### Deleted accounts
|
||||
|
||||
Auth drives it (see Auth's readme). `POST /internal/accounts/deleted` adds a tombstone in `deleted_user`: the user
|
||||
@@ -434,6 +459,8 @@ What the `local` profile does:
|
||||
- The browser still loads game pictures from the Steam and IGDB image servers; offline they stay gray.
|
||||
- "Sign in through Steam" still opens the real Steam page (no key needed). The dev user is already linked.
|
||||
- A request to WireMock that has no recording answers 404 and shows up in Core's log.
|
||||
- To see an IGDB link suggestion: add Hollow Knight by hand (game search, PS5). It shares IGDB's "same game" key with the
|
||||
Steam copy, so the link queue (auditor) lists the pair with the IGDB badge.
|
||||
|
||||
To change the recorded answers, edit the JSON in `local/wiremock/mappings` (which request) and
|
||||
`local/wiremock/__files` (the answer), then restart Core (it restarts the container). `LocalMocksParseTest` checks
|
||||
|
||||
Reference in new issue
Block a user