fix: validate all snowball order rows upfront, reject invalid ones with 400
PATCH /api/snowball/order silently skipped rows with bad ids or invalid snowball_order values via bare 'continue' — no feedback, partial updates. Now validates every item before touching the DB, returning 400 on the first bad entry. Also adds deleted_at IS NULL filter so soft-deleted bills are skipped instead of updated silently.
This commit is contained in:
parent
e41f413f61
commit
44320a7613
|
|
@ -214,22 +214,44 @@ router.patch('/order', (req, res) => {
|
|||
if (!Array.isArray(items)) {
|
||||
return res.status(400).json(standardizeError('Request body must be an array', 'VALIDATION_ERROR'));
|
||||
}
|
||||
if (items.length === 0) {
|
||||
return res.json({ success: true, updated: 0 });
|
||||
}
|
||||
|
||||
// Validate every row before touching the DB — no silent skips
|
||||
const parsed = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const row = items[i];
|
||||
const id = parseInt(row?.id, 10);
|
||||
const order = parseInt(row?.snowball_order, 10);
|
||||
if (!Number.isInteger(id) || id <= 0) {
|
||||
return res.status(400).json(standardizeError(
|
||||
`Item at index ${i} has an invalid id: ${JSON.stringify(row?.id)}`,
|
||||
'VALIDATION_ERROR',
|
||||
));
|
||||
}
|
||||
if (!Number.isInteger(order) || order < 0) {
|
||||
return res.status(400).json(standardizeError(
|
||||
`Item at index ${i} has an invalid snowball_order: ${JSON.stringify(row?.snowball_order)}`,
|
||||
'VALIDATION_ERROR',
|
||||
));
|
||||
}
|
||||
parsed.push({ id, order });
|
||||
}
|
||||
|
||||
const db = getDb();
|
||||
const userId = req.user.id;
|
||||
const update = db.prepare('UPDATE bills SET snowball_order = ? WHERE id = ? AND user_id = ?');
|
||||
const update = db.prepare(
|
||||
'UPDATE bills SET snowball_order = ? WHERE id = ? AND user_id = ? AND deleted_at IS NULL'
|
||||
);
|
||||
|
||||
db.transaction((rows) => {
|
||||
for (const row of rows) {
|
||||
const id = parseInt(row.id, 10);
|
||||
const order = parseInt(row.snowball_order, 10);
|
||||
if (!Number.isInteger(id) || id <= 0) continue;
|
||||
if (!Number.isInteger(order) || order < 0) continue;
|
||||
db.transaction(() => {
|
||||
for (const { id, order } of parsed) {
|
||||
update.run(order, id, userId);
|
||||
}
|
||||
})(items);
|
||||
})();
|
||||
|
||||
res.json({ success: true });
|
||||
res.json({ success: true, updated: parsed.length });
|
||||
});
|
||||
|
||||
// ── Snowball Plan helpers ─────────────────────────────────────────────────────
|
||||
|
|
|
|||
Loading…
Reference in New Issue