diff --git a/services/arbiter-3.0/src/routes/admin/players.js b/services/arbiter-3.0/src/routes/admin/players.js index eb7d1d2..6e1fdc5 100644 --- a/services/arbiter-3.0/src/routes/admin/players.js +++ b/services/arbiter-3.0/src/routes/admin/players.js @@ -8,6 +8,64 @@ router.get('/', async (req, res) => { res.render('admin/players/index', { title: 'Player Management', tiers: TIER_INFO }); }); +// Export all players as CSV +router.get('/export', async (req, res) => { + try { + const { rows: players } = await db.query(` + SELECT + s.discord_id, + u.minecraft_username, + u.minecraft_uuid, + COALESCE(u.is_staff, false) as is_staff, + s.tier_level, + s.status, + s.mrr_value, + s.is_lifetime, + s.stripe_customer_id, + s.created_at, + s.updated_at + FROM subscriptions s + LEFT JOIN users u ON s.discord_id = u.discord_id + ORDER BY s.updated_at DESC + `); + + // Build CSV + const headers = ['discord_id', 'minecraft_username', 'minecraft_uuid', 'is_staff', 'tier_level', 'tier_name', 'status', 'mrr_value', 'is_lifetime', 'stripe_customer_id', 'created_at', 'updated_at']; + + const csvRows = [headers.join(',')]; + + for (const player of players) { + const tierName = TIER_INFO[player.tier_level]?.name || 'Unknown'; + const row = [ + player.discord_id || '', + player.minecraft_username || '', + player.minecraft_uuid || '', + player.is_staff ? 'true' : 'false', + player.tier_level || '', + tierName, + player.status || '', + player.mrr_value || '0', + player.is_lifetime ? 'true' : 'false', + player.stripe_customer_id || '', + player.created_at ? new Date(player.created_at).toISOString() : '', + player.updated_at ? new Date(player.updated_at).toISOString() : '' + ].map(val => `"${String(val).replace(/"/g, '""')}"`); + csvRows.push(row.join(',')); + } + + const csv = csvRows.join('\n'); + const filename = `firefrost-players-${new Date().toISOString().split('T')[0]}.csv`; + + res.setHeader('Content-Type', 'text/csv'); + res.setHeader('Content-Disposition', `attachment; filename="${filename}"`); + res.send(csv); + + } catch (error) { + console.error('Export error:', error); + res.status(500).send('Error exporting players'); + } +}); + // HTMX Endpoint for the table body (Handles pagination, sorting, searching) router.get('/table', async (req, res) => { const page = parseInt(req.query.page) || 1; diff --git a/services/arbiter-3.0/src/views/admin/players/index.ejs b/services/arbiter-3.0/src/views/admin/players/index.ejs index b76ad9f..83d7933 100644 --- a/services/arbiter-3.0/src/views/admin/players/index.ejs +++ b/services/arbiter-3.0/src/views/admin/players/index.ejs @@ -9,6 +9,7 @@ hx-target="#player-table-body">
+ 📤 Export CSV