AeThex-Bot-Master/aethex-bot/commands/badges.js
sirpiglr 6feaad75db Update user profile displays to show custom avatar URLs when available
Modify commands like badges, profile, rank, and stats to prioritize and validate user-provided HTTP/HTTPS avatar URLs over default display avatars.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 566d93fe-73b9-4076-a03a-cb3263aa2dab
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/19PeEhC
Replit-Helium-Checkpoint-Created: true
2025-12-08 17:58:53 +00:00

126 lines
4.7 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const BADGE_INFO = {
'verified': { emoji: '✅', name: 'Verified', description: 'Linked Discord to AeThex' },
'early_adopter': { emoji: '🌟', name: 'Early Adopter', description: 'Joined during early access' },
'contributor': { emoji: '💎', name: 'Contributor', description: 'Contributed to the community' },
'creator': { emoji: '🎨', name: 'Creator', description: 'Published projects on Studio' },
'supporter': { emoji: '❤️', name: 'Supporter', description: 'Donated to the Foundation' },
'level_10': { emoji: '🔟', name: 'Level 10', description: 'Reached level 10' },
'level_25': { emoji: '🏆', name: 'Level 25', description: 'Reached level 25' },
'level_50': { emoji: '👑', name: 'Level 50', description: 'Reached level 50' },
'streak_7': { emoji: '🔥', name: 'Week Streak', description: '7 day daily claim streak' },
'streak_30': { emoji: '💪', name: 'Month Streak', description: '30 day daily claim streak' },
'helpful': { emoji: '🤝', name: 'Helpful', description: 'Helped 10+ community members' },
'bug_hunter': { emoji: '🐛', name: 'Bug Hunter', description: 'Reported a valid bug' },
};
module.exports = {
data: new SlashCommandBuilder()
.setName('badges')
.setDescription('View your earned badges across all platforms')
.addUserOption(option =>
option.setName('user')
.setDescription('User to view (defaults to yourself)')
.setRequired(false)
),
async execute(interaction, supabase, client) {
if (!supabase) {
return interaction.reply({ content: 'Database not configured.', ephemeral: true });
}
const target = interaction.options.getUser('user') || interaction.user;
await interaction.deferReply();
try {
const { data: link } = await supabase
.from('discord_links')
.select('user_id')
.eq('discord_id', target.id)
.single();
if (!link) {
return interaction.editReply({
embeds: [
new EmbedBuilder()
.setColor(0xff6b6b)
.setDescription(`${target.id === interaction.user.id ? 'You are' : `${target.tag} is`} not linked to AeThex.`)
]
});
}
const { data: profile } = await supabase
.from('user_profiles')
.select('username, avatar_url, badges, xp, daily_streak')
.eq('id', link.user_id)
.single();
let earnedBadges = [];
if (profile?.badges) {
earnedBadges = typeof profile.badges === 'string'
? JSON.parse(profile.badges)
: profile.badges;
}
earnedBadges.push('verified');
const xp = profile?.xp || 0;
const level = Math.floor(Math.sqrt(xp / 100));
if (level >= 10) earnedBadges.push('level_10');
if (level >= 25) earnedBadges.push('level_25');
if (level >= 50) earnedBadges.push('level_50');
const streak = profile?.daily_streak || 0;
if (streak >= 7) earnedBadges.push('streak_7');
if (streak >= 30) earnedBadges.push('streak_30');
earnedBadges = [...new Set(earnedBadges)];
// Validate avatar URL - must be http/https, not base64
let avatarUrl = target.displayAvatarURL();
if (profile?.avatar_url && profile.avatar_url.startsWith('http')) {
avatarUrl = profile.avatar_url;
}
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle(`${profile?.username || target.tag}'s Badges`)
.setThumbnail(avatarUrl)
.setTimestamp();
if (earnedBadges.length > 0) {
const badgeDisplay = earnedBadges.map(key => {
const info = BADGE_INFO[key];
if (info) {
return `${info.emoji} **${info.name}**\n${info.description}`;
}
return `🏅 **${key}**`;
}).join('\n\n');
embed.setDescription(badgeDisplay);
embed.addFields({ name: 'Total Badges', value: `${earnedBadges.length}`, inline: true });
} else {
embed.setDescription('No badges earned yet. Keep engaging to earn badges!');
}
const allBadgeKeys = Object.keys(BADGE_INFO);
const lockedBadges = allBadgeKeys.filter(k => !earnedBadges.includes(k));
if (lockedBadges.length > 0 && lockedBadges.length <= 6) {
const lockedDisplay = lockedBadges.map(key => {
const info = BADGE_INFO[key];
return `🔒 ${info.name}`;
}).join(', ');
embed.addFields({ name: 'Locked Badges', value: lockedDisplay });
}
await interaction.editReply({ embeds: [embed] });
} catch (error) {
console.error('Badges error:', error);
await interaction.editReply({ content: 'Failed to fetch badge data.' });
}
},
};