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();
}
});