From cf175b87e9d4a62ed9ee31d2b38c84462772a8a9 Mon Sep 17 00:00:00 2001 From: sirpiglr <49359077-sirpiglr@users.noreply.replit.com> Date: Mon, 8 Dec 2025 17:17:41 +0000 Subject: [PATCH] Remove local database connections and use Supabase exclusively Updates bot.js to remove PostgreSQL pool setup and pg dependency, switching all command logging and analytics to use Supabase. Replit-Commit-Author: Agent Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: a88f9025-8fdd-4882-8793-e15b62c35cda Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/7aeQEfK Replit-Helium-Checkpoint-Created: true --- .replit | 4 - aethex-bot/bot.js | 208 +++++++++++++++++++++------------------------- 2 files changed, 95 insertions(+), 117 deletions(-) diff --git a/.replit b/.replit index 7d084d4..5b6f647 100644 --- a/.replit +++ b/.replit @@ -22,10 +22,6 @@ externalPort = 80 localPort = 8080 externalPort = 8080 -[[ports]] -localPort = 33401 -externalPort = 3000 - [workflows] runButton = "Project" diff --git a/aethex-bot/bot.js b/aethex-bot/bot.js index 8ec819e..917d71f 100644 --- a/aethex-bot/bot.js +++ b/aethex-bot/bot.js @@ -12,7 +12,6 @@ const { createClient } = require("@supabase/supabase-js"); const http = require("http"); const fs = require("fs"); const path = require("path"); -const { Pool } = require("pg"); const WebSocket = require("ws"); // Dashboard HTML path @@ -69,97 +68,80 @@ if (process.env.SUPABASE_URL && process.env.SUPABASE_SERVICE_ROLE) { } // ============================================================================= -// POSTGRESQL DATABASE SETUP (Local database for analytics & config) -// ============================================================================= - -let pgPool = null; -if (process.env.DATABASE_URL) { - pgPool = new Pool({ - connectionString: process.env.DATABASE_URL, - max: 10, - idleTimeoutMillis: 30000, - connectionTimeoutMillis: 2000, - }); - pgPool.on('error', (err) => { - console.error('PostgreSQL pool error:', err.message); - }); - console.log("PostgreSQL connected"); -} else { - console.log("PostgreSQL not configured - using in-memory storage"); -} - -// ============================================================================= -// COMMAND LOGGING SYSTEM +// COMMAND LOGGING SYSTEM (Supabase-based) // ============================================================================= async function logCommand(data) { - if (!pgPool) return; + if (!supabase) return; try { - await pgPool.query( - `INSERT INTO command_logs (command_name, user_id, user_tag, guild_id, guild_name, channel_id, success, error_message, execution_time_ms) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`, - [ - data.commandName, - data.userId, - data.userTag, - data.guildId, - data.guildName, - data.channelId, - data.success, - data.errorMessage || null, - data.executionTime || null - ] - ); + await supabase.from('command_logs').insert({ + command_name: data.commandName, + user_id: data.userId, + user_tag: data.userTag, + guild_id: data.guildId, + guild_name: data.guildName, + channel_id: data.channelId, + success: data.success, + error_message: data.errorMessage || null, + execution_time_ms: data.executionTime || null + }); } catch (err) { console.error('Failed to log command:', err.message); } } async function getCommandAnalytics(days = 7) { - if (!pgPool) return { commands: [], hourly: [], daily: [], topUsers: [] }; + if (!supabase) return { commands: [], hourly: [], daily: [], topUsers: [] }; try { - const commandsResult = await pgPool.query( - `SELECT command_name, COUNT(*) as count, - SUM(CASE WHEN success THEN 1 ELSE 0 END) as success_count, - AVG(execution_time_ms) as avg_time - FROM command_logs - WHERE created_at > NOW() - INTERVAL '${days} days' - GROUP BY command_name - ORDER BY count DESC - LIMIT 20` - ); + const cutoffDate = new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString(); - const hourlyResult = await pgPool.query( - `SELECT EXTRACT(HOUR FROM created_at) as hour, COUNT(*) as count - FROM command_logs - WHERE created_at > NOW() - INTERVAL '24 hours' - GROUP BY hour - ORDER BY hour` - ); + const { data: logs } = await supabase + .from('command_logs') + .select('*') + .gte('created_at', cutoffDate); - const dailyResult = await pgPool.query( - `SELECT DATE(created_at) as date, COUNT(*) as count - FROM command_logs - WHERE created_at > NOW() - INTERVAL '${days} days' - GROUP BY date - ORDER BY date` - ); + if (!logs) return { commands: [], hourly: [], daily: [], topUsers: [] }; - const topUsersResult = await pgPool.query( - `SELECT user_id, user_tag, COUNT(*) as command_count - FROM command_logs - WHERE created_at > NOW() - INTERVAL '${days} days' - GROUP BY user_id, user_tag - ORDER BY command_count DESC - LIMIT 10` - ); + // Calculate command usage + const commandCounts = {}; + const userCounts = {}; + const hourlyActivity = Array(24).fill(0); + const dailyActivity = {}; - return { - commands: commandsResult.rows, - hourly: hourlyResult.rows, - daily: dailyResult.rows, - topUsers: topUsersResult.rows - }; + for (const log of logs) { + // Command counts + commandCounts[log.command_name] = (commandCounts[log.command_name] || 0) + 1; + + // User counts + const userKey = `${log.user_id}|${log.user_tag}`; + userCounts[userKey] = (userCounts[userKey] || 0) + 1; + + // Hourly + const hour = new Date(log.created_at).getHours(); + hourlyActivity[hour]++; + + // Daily + const dateKey = new Date(log.created_at).toISOString().split('T')[0]; + dailyActivity[dateKey] = (dailyActivity[dateKey] || 0) + 1; + } + + const commands = Object.entries(commandCounts) + .map(([name, count]) => ({ command_name: name, count })) + .sort((a, b) => b.count - a.count) + .slice(0, 20); + + const topUsers = Object.entries(userCounts) + .map(([key, count]) => { + const [user_id, user_tag] = key.split('|'); + return { user_id, user_tag, command_count: count }; + }) + .sort((a, b) => b.command_count - a.command_count) + .slice(0, 10); + + const hourly = hourlyActivity.map((count, hour) => ({ hour, count })); + const daily = Object.entries(dailyActivity).map(([date, count]) => ({ date, count })); + + return { commands, hourly, daily, topUsers }; } catch (err) { console.error('Failed to get command analytics:', err.message); return { commands: [], hourly: [], daily: [], topUsers: [] }; @@ -167,33 +149,29 @@ async function getCommandAnalytics(days = 7) { } async function getTotalCommandCount() { - if (!pgPool) return 0; + if (!supabase) return 0; try { - const result = await pgPool.query('SELECT COUNT(*) as count FROM command_logs'); - return parseInt(result.rows[0].count) || 0; + const { count } = await supabase.from('command_logs').select('*', { count: 'exact', head: true }); + return count || 0; } catch (err) { return 0; } } -// PostgreSQL-based server config functions +// Supabase-based server config functions async function saveServerConfigToDB(guildId, config) { - if (!pgPool) return false; + if (!supabase) return false; try { - await pgPool.query( - `INSERT INTO server_config (guild_id, welcome_channel, goodbye_channel, modlog_channel, level_up_channel, auto_role, verified_role, updated_at) - VALUES ($1, $2, $3, $4, $5, $6, $7, NOW()) - ON CONFLICT (guild_id) DO UPDATE SET - welcome_channel = EXCLUDED.welcome_channel, - goodbye_channel = EXCLUDED.goodbye_channel, - modlog_channel = EXCLUDED.modlog_channel, - level_up_channel = EXCLUDED.level_up_channel, - auto_role = EXCLUDED.auto_role, - verified_role = EXCLUDED.verified_role, - updated_at = NOW()`, - [guildId, config.welcome_channel, config.goodbye_channel, config.modlog_channel, - config.level_up_channel, config.auto_role, config.verified_role] - ); + await supabase.from('server_config').upsert({ + guild_id: guildId, + welcome_channel: config.welcome_channel, + goodbye_channel: config.goodbye_channel, + modlog_channel: config.modlog_channel, + level_up_channel: config.level_up_channel, + auto_role: config.auto_role, + verified_role: config.verified_role, + updated_at: new Date().toISOString() + }); return true; } catch (err) { console.error('Failed to save server config:', err.message); @@ -202,29 +180,30 @@ async function saveServerConfigToDB(guildId, config) { } async function getServerConfigFromDB(guildId) { - if (!pgPool) return null; + if (!supabase) return null; try { - const result = await pgPool.query( - 'SELECT * FROM server_config WHERE guild_id = $1', - [guildId] - ); - return result.rows[0] || null; + const { data } = await supabase + .from('server_config') + .select('*') + .eq('guild_id', guildId) + .single(); + return data || null; } catch (err) { console.error('Failed to get server config:', err.message); return null; } } -// Federation mappings with PostgreSQL +// Federation mappings with Supabase async function saveFederationMappingToDB(guildId, roleId, roleName) { - if (!pgPool) return false; + if (!supabase) return false; try { - await pgPool.query( - `INSERT INTO federation_mappings (guild_id, role_id, role_name, linked_at) - VALUES ($1, $2, $3, NOW()) - ON CONFLICT (guild_id, role_id) DO UPDATE SET role_name = EXCLUDED.role_name`, - [guildId, roleId, roleName] - ); + await supabase.from('federation_mappings').upsert({ + guild_id: guildId, + role_id: roleId, + role_name: roleName, + linked_at: new Date().toISOString() + }); return true; } catch (err) { console.error('Failed to save federation mapping:', err.message); @@ -233,10 +212,13 @@ async function saveFederationMappingToDB(guildId, roleId, roleName) { } async function getFederationMappingsFromDB() { - if (!pgPool) return []; + if (!supabase) return []; try { - const result = await pgPool.query('SELECT * FROM federation_mappings ORDER BY linked_at DESC'); - return result.rows; + const { data } = await supabase + .from('federation_mappings') + .select('*') + .order('linked_at', { ascending: false }); + return data || []; } catch (err) { console.error('Failed to get federation mappings:', err.message); return [];