AeThex-Bot-Master/attached_assets/bot1/discord-bot/events/messageCreate-announcements.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

237 lines
7.1 KiB
JavaScript

const { createClient } = require("@supabase/supabase-js");
// Initialize Supabase
const supabase = createClient(
process.env.SUPABASE_URL,
process.env.SUPABASE_SERVICE_ROLE,
);
const API_BASE = process.env.VITE_API_BASE || "https://api.aethex.dev";
// Channel IDs for syncing
const ANNOUNCEMENT_CHANNELS = process.env.DISCORD_ANNOUNCEMENT_CHANNELS
? process.env.DISCORD_ANNOUNCEMENT_CHANNELS.split(",")
: ["1435667453244866702"]; // Default to feed channel if env not set
// Arm affiliation mapping based on guild/channel name
const getArmAffiliation = (message) => {
const guildName = message.guild?.name?.toLowerCase() || "";
const channelName = message.channel?.name?.toLowerCase() || "";
const searchString = `${guildName} ${channelName}`.toLowerCase();
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"; // Default
};
module.exports = {
name: "messageCreate",
async execute(message, client, supabase) {
try {
// Ignore bot messages
if (message.author.bot) return;
// Only process messages in announcement channels
if (!ANNOUNCEMENT_CHANNELS.includes(message.channelId)) {
return;
}
// Skip empty messages
if (!message.content && message.attachments.size === 0) {
return;
}
console.log(
`[Announcements Sync] Processing message from ${message.author.tag} in #${message.channel.name}`,
);
// Get or create system admin user for announcements
let adminUser = await supabase
.from("user_profiles")
.select("id")
.eq("username", "aethex-announcements")
.single();
let authorId = adminUser.data?.id;
if (!authorId) {
// Create a system user if it doesn't exist
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 Sync] Could not get author ID");
return;
}
// Prepare message content
let content = message.content || "Announcement from Discord";
// Handle embeds (convert to text)
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 (images, videos)
let mediaUrl = null;
let mediaType = "none";
if (message.attachments.size > 0) {
const attachment = message.attachments.first();
if (attachment) {
mediaUrl = attachment.url;
const imageExtensions = [".jpg", ".jpeg", ".png", ".gif", ".webp"];
const videoExtensions = [".mp4", ".webm", ".mov", ".avi"];
const attachmentLower = attachment.name.toLowerCase();
if (imageExtensions.some((ext) => attachmentLower.endsWith(ext))) {
mediaType = "image";
} else if (
videoExtensions.some((ext) => attachmentLower.endsWith(ext))
) {
mediaType = "video";
}
}
}
// Determine arm affiliation
const armAffiliation = getArmAffiliation(message);
// Prepare post content JSON
const postContent = JSON.stringify({
text: content,
mediaUrl: mediaUrl,
mediaType: mediaType,
source: "discord",
discord_message_id: message.id,
discord_author: message.author.tag,
});
// Create post in AeThex
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 Sync] Failed to create post:",
insertError,
);
try {
await message.react("❌");
} catch (reactionError) {
console.warn(
"[Announcements Sync] Could not add reaction:",
reactionError,
);
}
return;
}
// Sync to Discord feed webhook if configured
if (process.env.DISCORD_FEED_WEBHOOK_URL && createdPost?.[0]) {
try {
const post = createdPost[0];
const armColors = {
labs: 0xfbbf24,
gameforge: 0x22c55e,
corp: 0x3b82f6,
foundation: 0xef4444,
devlink: 0x06b6d4,
nexus: 0xa855f7,
staff: 0x6366f1,
};
const embed = {
title: post.title,
description: content.substring(0, 1024),
color: armColors[armAffiliation] || 0x8b5cf6,
author: {
name: `${message.author.username} (${armAffiliation.toUpperCase()})`,
icon_url: message.author.displayAvatarURL(),
},
footer: {
text: "Synced from Discord",
},
timestamp: new Date().toISOString(),
};
await fetch(process.env.DISCORD_FEED_WEBHOOK_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: "AeThex Community Feed",
embeds: [embed],
}),
});
} catch (webhookError) {
console.warn(
"[Announcements Sync] Failed to sync to webhook:",
webhookError,
);
}
}
console.log(
`[Announcements Sync] ✅ Posted announcement from Discord to AeThex (${armAffiliation})`,
);
// React with success emoji
try {
await message.react("✅");
} catch (reactionError) {
console.warn(
"[Announcements Sync] Could not add success reaction:",
reactionError,
);
}
} catch (error) {
console.error("[Announcements Sync] Unexpected error:", error);
try {
await message.react("⚠️");
} catch (reactionError) {
console.warn(
"[Announcements Sync] Could not add warning reaction:",
reactionError,
);
}
}
},
};