From c7c4705c528d5b4479792ca8cd89c3e242e0cbbd Mon Sep 17 00:00:00 2001 From: sirpiglr <49359077-sirpiglr@users.noreply.replit.com> Date: Sat, 13 Dec 2025 10:52:52 +0000 Subject: [PATCH] Add a daily scheduler to evaluate and update federation trust levels Introduces a new daily scheduler in `bot.js` to evaluate federation server trust levels based on member count and other factors. Includes an API endpoint `/api/federation/guild/:guildId` in `webServer.js` to fetch guild-specific federation status, and updates `dashboard.html` to display this information. Replit-Commit-Author: Agent Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 342196c8-6efc-4cab-9367-2e90abd6f3e1 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/HdH3K6u Replit-Helium-Checkpoint-Created: true --- aethex-bot/bot.js | 119 +++++++++++++++++++++++++++++ aethex-bot/public/dashboard.html | 124 +++++++++++++++++++++++++++++++ aethex-bot/server/webServer.js | 70 +++++++++++++++++ 3 files changed, 313 insertions(+) diff --git a/aethex-bot/bot.js b/aethex-bot/bot.js index 794459c..780e72a 100644 --- a/aethex-bot/bot.js +++ b/aethex-bot/bot.js @@ -2781,6 +2781,7 @@ client.once("clientReady", async () => { // Start automatic backup scheduler if (supabase) { startAutoBackupScheduler(client, supabase); + startFederationTrustEvaluator(client, supabase); } }); @@ -2863,6 +2864,124 @@ async function startAutoBackupScheduler(discordClient, supabaseClient) { console.log('[Backup] Scheduler started - checking every hour'); } +// ============================================================================= +// FEDERATION TRUST LEVEL PROGRESSION SCHEDULER +// ============================================================================= + +async function startFederationTrustEvaluator(discordClient, supabaseClient) { + console.log('[Federation] Starting trust level evaluation scheduler...'); + + const { calculateTrustLevel, getTrustLevelInfo } = require('./utils/trustLevels'); + + // Evaluate trust levels daily + setInterval(async () => { + try { + const { data: servers } = await supabaseClient + .from('federation_servers') + .select('*') + .eq('status', 'approved'); + + if (!servers || servers.length === 0) return; + + let upgrades = 0; + let downgrades = 0; + + for (const server of servers) { + // Get current member count from Discord + const guild = discordClient.guilds.cache.get(server.guild_id); + const memberCount = guild?.memberCount || server.member_count || 0; + + // Update member count in database + if (guild && memberCount !== server.member_count) { + await supabaseClient + .from('federation_servers') + .update({ member_count: memberCount }) + .eq('guild_id', server.guild_id); + } + + // Calculate new trust level + const serverData = { ...server, member_count: memberCount }; + const newLevel = calculateTrustLevel(serverData); + const currentLevel = server.trust_level || 'bronze'; + + if (newLevel !== currentLevel) { + const oldInfo = getTrustLevelInfo(currentLevel); + const newInfo = getTrustLevelInfo(newLevel); + + await supabaseClient + .from('federation_servers') + .update({ + trust_level: newLevel, + updated_at: new Date().toISOString(), + last_activity: new Date().toISOString() + }) + .eq('guild_id', server.guild_id); + + // Determine if upgrade or downgrade + const levels = ['bronze', 'silver', 'gold', 'platinum']; + const isUpgrade = levels.indexOf(newLevel) > levels.indexOf(currentLevel); + + if (isUpgrade) { + upgrades++; + console.log(`[Federation] ${server.guild_name}: ${oldInfo.emoji} ${oldInfo.name} → ${newInfo.emoji} ${newInfo.name} (UPGRADE)`); + } else { + downgrades++; + console.log(`[Federation] ${server.guild_name}: ${oldInfo.emoji} ${oldInfo.name} → ${newInfo.emoji} ${newInfo.name} (DOWNGRADE)`); + } + + // Send notification to the server if we can + if (guild) { + try { + const systemChannel = guild.systemChannel; + if (systemChannel) { + const { EmbedBuilder } = require('discord.js'); + const embed = new EmbedBuilder() + .setColor(newInfo.color) + .setTitle(`${newInfo.emoji} Federation Trust Level ${isUpgrade ? 'Upgrade' : 'Change'}!`) + .setDescription(isUpgrade + ? `Congratulations! Your server has been promoted to **${newInfo.name}** tier in the Federation.` + : `Your server's Federation tier has been adjusted to **${newInfo.name}**.`) + .addFields( + { name: 'Previous Tier', value: `${oldInfo.emoji} ${oldInfo.name}`, inline: true }, + { name: 'New Tier', value: `${newInfo.emoji} ${newInfo.name}`, inline: true } + ) + .setTimestamp(); + + await systemChannel.send({ embeds: [embed] }).catch(() => {}); + } + } catch (e) { + // Silent fail for notifications + } + } + } + } + + if (upgrades > 0 || downgrades > 0) { + console.log(`[Federation] Trust evaluation complete: ${upgrades} upgrades, ${downgrades} downgrades`); + } + } catch (error) { + console.error('[Federation] Trust evaluation error:', error.message); + } + }, 24 * 60 * 60 * 1000); // Evaluate daily + + // Also run immediately on startup (after a short delay) + setTimeout(async () => { + console.log('[Federation] Running initial trust level evaluation...'); + try { + const { data: servers } = await supabaseClient + .from('federation_servers') + .select('*') + .eq('status', 'approved'); + + console.log(`[Federation] Monitoring ${servers?.length || 0} federation servers`); + } catch (e) { + console.error('[Federation] Initial check error:', e.message); + } + }, 10000); + + console.log('[Federation] Trust evaluator started - checking daily'); +} + // ============================================================================= // ERROR HANDLING // ============================================================================= diff --git a/aethex-bot/public/dashboard.html b/aethex-bot/public/dashboard.html index ff1a649..e832d17 100644 --- a/aethex-bot/public/dashboard.html +++ b/aethex-bot/public/dashboard.html @@ -2241,6 +2241,19 @@

Manage your federation membership, view bans, and applications

+
+
+

Your Server Status

+ +
+
+
+
+

Loading status...

+
+
+
+
Member Servers
@@ -3517,7 +3530,118 @@ } } + async function loadFederationGuildStatus() { + if (!currentGuild) return; + const container = document.getElementById('fedGuildStatusContent'); + const badge = document.getElementById('fedMemberBadge'); + + try { + const res = await fetch('/api/federation/guild/' + currentGuild); + const data = await res.json(); + + if (!data.member) { + badge.style.display = 'none'; + container.innerHTML = ` +
+
🌐
+

This server is not a Federation member.

+

Join the Federation to get cross-server protection from raiders, scammers, and malicious users.

+ Learn More & Apply +
+ `; + return; + } + + badge.style.display = 'inline-block'; + badge.style.background = 'linear-gradient(135deg, var(--primary), #3b82f6)'; + badge.style.color = 'white'; + badge.style.padding = '0.25rem 0.75rem'; + badge.style.borderRadius = '20px'; + badge.style.fontSize = '0.75rem'; + badge.style.fontWeight = '600'; + + const tl = data.trustLevel; + const rep = data.reputation; + const prog = data.progression; + + let progressHtml = ''; + if (prog.nextLevel && prog.progress) { + const p = prog.progress; + progressHtml = ` +
+

Progress to ${prog.nextLevelInfo?.emoji || ''} ${prog.nextLevelInfo?.name || prog.nextLevel}

+
+
+
+ Members + ${p.members.current.toLocaleString()} / ${p.members.required.toLocaleString()} ${p.members.met ? '✓' : ''} +
+
+
+
+
+ Days in Federation + ${p.days.current} / ${p.days.required} ${p.days.met ? '✓' : ''} +
+
+
+
+
+ Reputation Score + ${p.reputation.current} / ${p.reputation.required} ${p.reputation.met ? '✓' : ''} +
+
+
+
+ ${prog.allMet ? '

✨ All requirements met! Upgrade will be applied in the next evaluation.

' : ''} +
+ `; + } else { + progressHtml = '

🎉 Maximum trust level reached!

'; + } + + container.innerHTML = ` +
+
+
${tl.emoji}
+
${tl.name} Tier
+
Trust Level
+
+
+
+
Reputation Score
+
${rep.score.toLocaleString()}
+
+
+
Reports Submitted
+
${rep.reports_submitted}
+
+
+
False Positives
+
${rep.false_positives}
+
+
+
+
Current Benefits
+
+
🛡️ Auto Action: ${tl.benefits.autoAction.toUpperCase()}
+
⚠️ Severity Threshold: ${tl.benefits.severityThreshold.toUpperCase()}
+
📋 Directory Listing: ${tl.benefits.directoryListing ? 'Yes' : 'No'}
+
⭐ Featured Eligible: ${tl.benefits.featuredEligible ? 'Yes' : 'No'}
+
🤝 Partnership Limit: ${tl.benefits.partnershipLimit}
+
+
+
+ ${progressHtml} + `; + } catch (e) { + console.error('Failed to load federation guild status:', e); + container.innerHTML = '
Failed to load federation status
'; + } + } + function loadFederationData() { + loadFederationGuildStatus(); loadFederationStats(); loadFederationServers(); loadFederationBans(); diff --git a/aethex-bot/server/webServer.js b/aethex-bot/server/webServer.js index 8252e16..ba17216 100644 --- a/aethex-bot/server/webServer.js +++ b/aethex-bot/server/webServer.js @@ -1497,6 +1497,76 @@ function createWebServer(discordClient, supabase, options = {}) { } }); + app.get('/api/federation/guild/:guildId', async (req, res) => { + if (!supabase) { + return res.status(503).json({ error: 'Database not available' }); + } + + const { guildId } = req.params; + + try { + const { data: server } = await supabase + .from('federation_servers') + .select('*') + .eq('guild_id', guildId) + .maybeSingle(); + + if (!server) { + return res.json({ + member: false, + message: 'This server is not a federation member' + }); + } + + const { getProgressToNextLevel, getTrustLevelInfo, TRUST_LEVELS } = require('../utils/trustLevels'); + + const trustLevelInfo = getTrustLevelInfo(server.trust_level || 'bronze'); + const progression = getProgressToNextLevel(server); + + const guild = discordClient.guilds.cache.get(guildId); + const memberCount = guild?.memberCount || server.member_count || 0; + + res.json({ + member: true, + server: { + guild_id: server.guild_id, + guild_name: server.guild_name, + guild_icon: server.guild_icon, + member_count: memberCount, + tier: server.tier, + status: server.status, + joined_at: server.created_at, + joined_federation_at: server.joined_federation_at || server.created_at + }, + trustLevel: { + level: server.trust_level || 'bronze', + name: trustLevelInfo.name, + emoji: trustLevelInfo.emoji, + color: trustLevelInfo.color, + benefits: trustLevelInfo.benefits + }, + reputation: { + score: server.reputation_score || 0, + reports_submitted: server.reports_submitted || 0, + false_positives: server.false_positives || 0, + last_activity: server.last_activity + }, + progression: { + nextLevel: progression.nextLevel, + nextLevelInfo: progression.nextLevelInfo ? { + name: progression.nextLevelInfo.name, + emoji: progression.nextLevelInfo.emoji + } : null, + progress: progression.progress, + allMet: progression.allMet + } + }); + } catch (error) { + console.error('Failed to fetch guild federation stats:', error); + res.status(500).json({ error: 'Failed to fetch federation stats' }); + } + }); + // ============ STRIPE PAYMENT API ============ app.post('/api/stripe/create-checkout', async (req, res) => {