diff --git a/services/arbiter-3.0/src/routes/admin/grace.js b/services/arbiter-3.0/src/routes/admin/grace.js index a97be19..fb0ae9b 100644 --- a/services/arbiter-3.0/src/routes/admin/grace.js +++ b/services/arbiter-3.0/src/routes/admin/grace.js @@ -51,21 +51,34 @@ router.post('/:discord_id/extend', async (req, res) => { const adminId = req.user.id; const adminUsername = req.user.username; + const client = await db.pool.connect(); + try { - await db.query(` + // BEGIN TRANSACTION + await client.query('BEGIN'); + + await client.query(` UPDATE subscriptions SET grace_period_ends_at = grace_period_ends_at + INTERVAL '24 hours' WHERE discord_id = $1 AND status = 'grace_period' `, [discord_id]); - await db.query(` + await client.query(` INSERT INTO admin_audit_log (admin_discord_id, admin_username, action_type, target_identifier, details) VALUES ($1, $2, 'extend_grace_period', $3, '{"extension": "24h"}') `, [adminId, adminUsername, discord_id]); + // COMMIT TRANSACTION + await client.query('COMMIT'); + res.send(`✅ Extended 24h`); } catch (error) { + // ROLLBACK on error + await client.query('ROLLBACK'); + console.error('Grace period extension error:', error); res.status(500).send(`❌ Error`); + } finally { + client.release(); } }); @@ -75,21 +88,34 @@ router.post('/:discord_id/manual', async (req, res) => { const adminId = req.user.id; const adminUsername = req.user.username; + const client = await db.pool.connect(); + try { - await db.query(` + // BEGIN TRANSACTION + await client.query('BEGIN'); + + await client.query(` UPDATE subscriptions SET status = 'active', grace_period_started_at = NULL, grace_period_ends_at = NULL WHERE discord_id = $1 `, [discord_id]); - await db.query(` + await client.query(` INSERT INTO admin_audit_log (admin_discord_id, admin_username, action_type, target_identifier, details) VALUES ($1, $2, 'manual_payment_override', $3, '{"reason": "admin_override"}') `, [adminId, adminUsername, discord_id]); + // COMMIT TRANSACTION + await client.query('COMMIT'); + res.send(`✅ Activated`); } catch (error) { + // ROLLBACK on error + await client.query('ROLLBACK'); + console.error('Manual payment override error:', error); res.status(500).send(`❌ Error`); + } finally { + client.release(); } }); diff --git a/services/arbiter-3.0/src/routes/admin/players.js b/services/arbiter-3.0/src/routes/admin/players.js index 378bf1b..6528f7c 100644 --- a/services/arbiter-3.0/src/routes/admin/players.js +++ b/services/arbiter-3.0/src/routes/admin/players.js @@ -37,15 +37,20 @@ router.post('/:discord_id/tier', async (req, res) => { const { discord_id } = req.params; const { tier_level } = req.body; + const client = await db.pool.connect(); + try { // Validate tier exists if (!TIER_INFO[tier_level]) { return res.status(400).send('Invalid tier'); } + // BEGIN TRANSACTION + await client.query('BEGIN'); + // Update tier in database const tierInfo = TIER_INFO[tier_level]; - await db.query(` + await client.query(` UPDATE subscriptions SET tier_level = $1, mrr_value = $2, updated_at = NOW() WHERE discord_id = $3 @@ -55,17 +60,24 @@ router.post('/:discord_id/tier', async (req, res) => { // This will be implemented when Discord bot integration is ready // Create audit log entry - await db.query(` + await client.query(` INSERT INTO admin_audit_log (admin_discord_id, action, target_discord_id, details) VALUES ($1, 'tier_change', $2, $3) `, [req.user.id, discord_id, `Changed tier to ${tierInfo.name}`]); + // COMMIT TRANSACTION + await client.query('COMMIT'); + // Return success (htmx will handle UI update) res.send('OK'); } catch (error) { + // ROLLBACK on error + await client.query('ROLLBACK'); console.error('Tier change error:', error); res.status(500).send('Error updating tier'); + } finally { + client.release(); } }); @@ -73,29 +85,41 @@ router.post('/:discord_id/tier', async (req, res) => { router.post('/:discord_id/staff', async (req, res) => { const { discord_id } = req.params; + const client = await db.pool.connect(); + try { + // BEGIN TRANSACTION + await client.query('BEGIN'); + // Toggle staff status - await db.query(` + await client.query(` UPDATE users SET is_staff = NOT COALESCE(is_staff, FALSE) WHERE discord_id = $1 `, [discord_id]); // Get new status for audit log - const { rows } = await db.query(`SELECT is_staff FROM users WHERE discord_id = $1`, [discord_id]); + const { rows } = await client.query(`SELECT is_staff FROM users WHERE discord_id = $1`, [discord_id]); const newStatus = rows[0]?.is_staff ? 'Staff' : 'Non-Staff'; // Create audit log entry - await db.query(` + await client.query(` INSERT INTO admin_audit_log (admin_discord_id, action, target_discord_id, details) VALUES ($1, 'staff_toggle', $2, $3) `, [req.user.id, discord_id, `Changed to ${newStatus}`]); + // COMMIT TRANSACTION + await client.query('COMMIT'); + res.send('OK'); } catch (error) { + // ROLLBACK on error + await client.query('ROLLBACK'); console.error('Staff toggle error:', error); res.status(500).send('Error updating staff status'); + } finally { + client.release(); } });