fix(market): relisting an expired auction actually relists it
The client's relist arrives as a fresh ISStart (`POST /auctionhouse`) for an item that ALREADY has a listing row, so `create_listing` hit a primary-key conflict. The handler treated `Err(Conflict)` as success: it logged `listed=true`, handed the client its trade id, and persisted nothing. The stale row kept its old `created_at`, so the card stayed expired and the relist appeared to do nothing -- observed live, with the client's price-limits fetch and the ISStart POST both in the log. The PK conflict IS the relist path. `relist_listing` now resets `created_at` to now and takes the new prices and duration, so the auction actually returns to the market with a fresh countdown. Refuses to revive a `sold` or `reserved` row: re-opening a sold auction would sell the same card twice. `cancelled` rows ARE relistable (the card is back in the pile). Missing rows report NotFound rather than silently succeeding. The failure paths still ack so the screen cannot wedge, but they now say `relisted=false reason=...` in the log instead of claiming success. Three store tests: the clock/price reset, the sold+reserved revival guard (plus the cancelled-is-relistable case), and NotFound. 336 tests pass, 0 failed, clippy clean.
This commit is contained in:
@@ -302,13 +302,48 @@ pub async fn handle_market_list(
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) | Err(MarketError::Conflict) => {
|
||||
Ok(_) => {
|
||||
eprintln!(
|
||||
"utas-host owner=RUST route=market-list POST item_id={} listed=true trade_id={trade_id}",
|
||||
r.item_id
|
||||
);
|
||||
ok_json(&json!({ "id": trade_id }))
|
||||
}
|
||||
// A row for this item already exists, so this POST is a RELIST.
|
||||
// FIFA 17 relists by re-sending ISStart, so the PK conflict is the
|
||||
// normal relist path — NOT an error, and NOT a success to swallow.
|
||||
// Acking it without resetting the clock is why relisting an expired
|
||||
// card appeared to do nothing: the client got its id back while the
|
||||
// stale row stayed expired.
|
||||
Err(MarketError::Conflict) => {
|
||||
match store
|
||||
.relist_listing(
|
||||
&listing_id,
|
||||
r.start,
|
||||
r.buy_now,
|
||||
r.duration,
|
||||
r.item_json.as_deref(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
eprintln!(
|
||||
"utas-host owner=RUST route=market-list POST item_id={} relisted=true trade_id={trade_id}",
|
||||
r.item_id
|
||||
);
|
||||
ok_json(&json!({ "id": trade_id }))
|
||||
}
|
||||
// Sold or in-flight: never revive it. Ack so the screen does
|
||||
// not wedge, but say so plainly in the log.
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"utas-host owner=RUST route=market-list POST item_id={} relisted=false reason={e:?} trade_id={trade_id}",
|
||||
r.item_id
|
||||
);
|
||||
ok_json(&json!({ "id": trade_id }))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => json_body(503, &json!({ "error": "market_store" })),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user