fix(api): validate quantity on POST /api/user-cards (#46)
Match decks handler parseInt/NaN guard so non-numeric quantities cannot corrupt user_cards row counts from scanner add paths. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
66717c4198
commit
30b21b42c5
3 changed files with 34 additions and 4 deletions
|
|
@ -24,8 +24,8 @@ Reports posted to [PR #44](https://github.com/varutasu/tcg-vault/pull/44#issueco
|
|||
|
||||
| Slug | Priority | Source |
|
||||
| --- | --- | --- |
|
||||
| `scanner-redesign-a11y-fixes` | P1 | **In progress** — PR pending |
|
||||
| `scanner-user-cards-quantity-guard` | P2 | Reviewer — parseInt/NaN guard parity with decks handler |
|
||||
| `scanner-redesign-a11y-fixes` | P1 | **RESOLVED** — PR #45 |
|
||||
| `scanner-user-cards-quantity-guard` | P2 | **In progress** — PR pending |
|
||||
| `test-scanner-redesign-surfaces` | P2 | Reviewer — unit tests for new components + upload route |
|
||||
| `document-condition-foil-destination-semantics` | P3 | Reviewer — clarify or migrate condition/foil for collection/deck rows |
|
||||
| `camera-scanner-token-cleanup` | P3 | Design system — replace hardcoded hex overlay colors in CameraScanner |
|
||||
|
|
|
|||
25
.convoys/scanner-user-cards-quantity-guard.md
Normal file
25
.convoys/scanner-user-cards-quantity-guard.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
name: scanner-user-cards-quantity-guard
|
||||
classification: fix
|
||||
success_metric: |
|
||||
POST /api/user-cards rejects non-numeric and sub-1 quantity with 400, matching
|
||||
the decks/[id]/cards handler contract.
|
||||
depends_on:
|
||||
- redesign-scanner-flow
|
||||
status: open
|
||||
created: 2026-05-27
|
||||
---
|
||||
|
||||
# Convoy: scanner-user-cards-quantity-guard
|
||||
|
||||
P2 follow-up from `audit-redesign-scanner-flow-44` reviewer report.
|
||||
|
||||
## Scope
|
||||
|
||||
- `pages/api/user-cards.js` — `parseInt(quantity, 10)` + NaN / `< 1` guard on POST
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
1. `quantity: "abc"` → 400 `Quantity must be at least 1`
|
||||
2. `quantity: 0` → 400
|
||||
3. Valid integer ≥ 1 uses parsed value for INSERT and UPDATE increment
|
||||
|
|
@ -21,6 +21,11 @@ export default async function handler(req, res) {
|
|||
return res.status(400).json({ error: 'Card ID is required' });
|
||||
}
|
||||
|
||||
const parsedQuantity = parseInt(quantity, 10);
|
||||
if (Number.isNaN(parsedQuantity) || parsedQuantity < 1) {
|
||||
return res.status(400).json({ error: 'Quantity must be at least 1' });
|
||||
}
|
||||
|
||||
const scanImageUrl =
|
||||
typeof scanImageUrlRaw === 'string' && scanImageUrlRaw.trim().length > 0
|
||||
? scanImageUrlRaw.trim()
|
||||
|
|
@ -34,7 +39,7 @@ export default async function handler(req, res) {
|
|||
|
||||
if (existingResult.rows.length > 0) {
|
||||
// Update quantity; preserve existing scan image unless a new URL is supplied
|
||||
const newQuantity = existingResult.rows[0].quantity + quantity;
|
||||
const newQuantity = existingResult.rows[0].quantity + parsedQuantity;
|
||||
await sql`
|
||||
UPDATE user_cards
|
||||
SET quantity = ${newQuantity},
|
||||
|
|
@ -46,7 +51,7 @@ export default async function handler(req, res) {
|
|||
// Insert new record
|
||||
await sql`
|
||||
INSERT INTO user_cards (user_id, card_id, quantity, condition, is_foil, scan_image_url)
|
||||
VALUES (${user.userId}, ${cardId}, ${quantity}, ${condition}, ${is_foil}, ${scanImageUrl})
|
||||
VALUES (${user.userId}, ${cardId}, ${parsedQuantity}, ${condition}, ${is_foil}, ${scanImageUrl})
|
||||
`;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue