AeThex-Bot-Master/attached_assets/bot1/discord-bot/events/messageCreate.js
sirpiglr 02e50ed478 Add Discord bot functionality for AeThex platform integration
Adds two Node.js Discord bots for the AeThex platform, enabling features such as account linking, role management, profile viewing, community posts, and more, with extensive Supabase integration.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: e72fc1b7-94bd-4d6c-801f-cbac2fae245c
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: f8fda02a-6ff3-4bdf-87d4-fdbef7f9a2ce
Replit-Helium-Checkpoint-Created: true
2025-12-06 21:44:38 +00:00

320 lines
9.6 KiB
JavaScript

const { createClient } = require("@supabase/supabase-js");
// Initialize Supabase
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_SERVICE_ROLE,
);
const FEED_CHANNEL_ID = process.env.DISCORD_FEED_CHANNEL_ID;
const FEED_GUILD_ID = process.env.DISCORD_FEED_GUILD_ID;
const API_BASE = process.env.VITE_API_BASE || "https://api.aethex.dev";
// Announcement channels to sync to feed
const ANNOUNCEMENT_CHANNELS = process.env.DISCORD_ANNOUNCEMENT_CHANNELS
? process.env.DISCORD_ANNOUNCEMENT_CHANNELS.split(",").map((id) => id.trim())
: [];
// Helper: Get arm affiliation from message context
function getArmAffiliation(message) {
const guildName = message.guild?.name?.toLowerCase() || "";
const channelName = message.channel?.name?.toLowerCase() || "";
const searchString = `${guildName} ${channelName}`;
if (searchString.includes("gameforge")) return "gameforge";
if (searchString.includes("corp")) return "corp";
if (searchString.includes("foundation")) return "foundation";
if (searchString.includes("devlink") || searchString.includes("dev-link"))
return "devlink";
if (searchString.includes("nexus")) return "nexus";
if (searchString.includes("staff")) return "staff";
return "labs";
}
// Handle announcements from designated channels
async function handleAnnouncementSync(message) {
try {
console.log(
`[Announcements] Processing from ${message.author.tag} in #${message.channel.name}`,
);
// Get or create system announcement user
let { data: adminUser } = await supabase
.from("user_profiles")
.select("id")
.eq("username", "aethex-announcements")
.single();
let authorId = adminUser?.id;
if (!authorId) {
const { data: newUser } = await supabase
.from("user_profiles")
.insert({
username: "aethex-announcements",
full_name: "AeThex Announcements",
avatar_url: "https://aethex.dev/logo.png",
})
.select("id");
authorId = newUser?.[0]?.id;
}
if (!authorId) {
console.error("[Announcements] Could not get author ID");
await message.react("❌");
return;
}
// Prepare content
let content = message.content || "Announcement from Discord";
// Handle embeds
if (message.embeds.length > 0) {
const embed = message.embeds[0];
if (embed.title) content = `**${embed.title}**\n\n${content}`;
if (embed.description) content += `\n\n${embed.description}`;
}
// Handle attachments
let mediaUrl = null;
let mediaType = "none";
if (message.attachments.size > 0) {
const attachment = message.attachments.first();
if (attachment) {
mediaUrl = attachment.url;
const attachmentLower = attachment.name.toLowerCase();
if (
[".jpg", ".jpeg", ".png", ".gif", ".webp"].some((ext) =>
attachmentLower.endsWith(ext),
)
) {
mediaType = "image";
} else if (
[".mp4", ".webm", ".mov", ".avi"].some((ext) =>
attachmentLower.endsWith(ext),
)
) {
mediaType = "video";
}
}
}
// Determine arm
const armAffiliation = getArmAffiliation(message);
// Prepare post content
const postContent = JSON.stringify({
text: content,
mediaUrl: mediaUrl,
mediaType: mediaType,
source: "discord",
discord_message_id: message.id,
discord_channel: message.channel.name,
});
// Create post
const { data: createdPost, error: insertError } = await supabase
.from("community_posts")
.insert({
title: content.substring(0, 100) || "Discord Announcement",
content: postContent,
arm_affiliation: armAffiliation,
author_id: authorId,
tags: ["discord", "announcement"],
category: "announcement",
is_published: true,
likes_count: 0,
comments_count: 0,
})
.select(
`id, title, content, arm_affiliation, author_id, created_at, likes_count, comments_count,
user_profiles!community_posts_author_id_fkey (id, username, full_name, avatar_url)`,
);
if (insertError) {
console.error("[Announcements] Post creation failed:", insertError);
await message.react("❌");
return;
}
console.log(`[Announcements] ✅ Synced to AeThex (${armAffiliation} arm)`);
await message.react("✅");
} catch (error) {
console.error("[Announcements] Error:", error);
try {
await message.react("⚠️");
} catch (e) {
console.warn("[Announcements] Could not react:", e);
}
}
}
module.exports = {
name: "messageCreate",
async execute(message, client) {
// Ignore bot messages and empty messages
if (message.author.bot) return;
if (!message.content && message.attachments.size === 0) return;
// Check if this is an announcement to sync
if (
ANNOUNCEMENT_CHANNELS.length > 0 &&
ANNOUNCEMENT_CHANNELS.includes(message.channelId)
) {
return handleAnnouncementSync(message);
}
// Check if this is in the feed channel (for user-generated posts)
if (FEED_CHANNEL_ID && message.channelId !== FEED_CHANNEL_ID) {
return;
}
if (FEED_GUILD_ID && message.guildId !== FEED_GUILD_ID) {
return;
}
try {
// Get user's linked AeThex account
const { data: linkedAccount, error } = await supabase
.from("discord_links")
.select("user_id")
.eq("discord_user_id", message.author.id)
.single();
if (error || !linkedAccount) {
try {
await message.author.send(
"To have your message posted to AeThex, please link your Discord account! Use `/verify` command.",
);
} catch (dmError) {
console.warn("[Feed Sync] Could not send DM to user:", dmError);
}
return;
}
// Get user profile
const { data: userProfile, error: profileError } = await supabase
.from("user_profiles")
.select("id, username, full_name, avatar_url")
.eq("id", linkedAccount.user_id)
.single();
if (profileError || !userProfile) {
console.error(
"[Feed Sync] Could not fetch user profile:",
profileError,
);
return;
}
// Prepare content
let content = message.content || "Shared a message on Discord";
let mediaUrl = null;
let mediaType = "none";
if (message.attachments.size > 0) {
const attachment = message.attachments.first();
if (attachment) {
mediaUrl = attachment.url;
const attachmentLower = attachment.name.toLowerCase();
if (
[".jpg", ".jpeg", ".png", ".gif", ".webp"].some((ext) =>
attachmentLower.endsWith(ext),
)
) {
mediaType = "image";
} else if (
[".mp4", ".webm", ".mov", ".avi"].some((ext) =>
attachmentLower.endsWith(ext),
)
) {
mediaType = "video";
}
}
}
// Determine arm affiliation
let armAffiliation = "labs";
const guild = message.guild;
if (guild) {
const guildNameLower = guild.name.toLowerCase();
if (guildNameLower.includes("gameforge")) armAffiliation = "gameforge";
else if (guildNameLower.includes("corp")) armAffiliation = "corp";
else if (guildNameLower.includes("foundation"))
armAffiliation = "foundation";
else if (guildNameLower.includes("devlink")) armAffiliation = "devlink";
else if (guildNameLower.includes("nexus")) armAffiliation = "nexus";
else if (guildNameLower.includes("staff")) armAffiliation = "staff";
}
// Prepare post content
const postContent = JSON.stringify({
text: content,
mediaUrl: mediaUrl,
mediaType: mediaType,
});
// Create post
const { data: createdPost, error: insertError } = await supabase
.from("community_posts")
.insert({
title: content.substring(0, 100) || "Discord Shared Message",
content: postContent,
arm_affiliation: armAffiliation,
author_id: userProfile.id,
tags: ["discord"],
category: null,
is_published: true,
likes_count: 0,
comments_count: 0,
})
.select(
`id, title, content, arm_affiliation, author_id, created_at, updated_at, likes_count, comments_count,
user_profiles!community_posts_author_id_fkey (id, username, full_name, avatar_url)`,
);
if (insertError) {
console.error("[Feed Sync] Failed to create post:", insertError);
try {
await message.react("❌");
} catch (e) {
console.warn("[Feed Sync] Could not add reaction:", e);
}
return;
}
console.log(`[Feed Sync] ✅ Posted from ${message.author.tag} to AeThex`);
try {
await message.react("✅");
} catch (reactionError) {
console.warn(
"[Feed Sync] Could not add success reaction:",
reactionError,
);
}
try {
await message.author.send(
`✅ Your message was posted to AeThex! Check it out at https://aethex.dev/feed`,
);
} catch (dmError) {
console.warn("[Feed Sync] Could not send confirmation DM:", dmError);
}
} catch (error) {
console.error("[Feed Sync] Unexpected error:", error);
try {
await message.react("⚠️");
} catch (e) {
console.warn("[Feed Sync] Could not add warning reaction:", e);
}
}
},
};