Discord Bot - Announcements sync to feed
cgen-c294d477f916443cad0617064edff7b8
This commit is contained in:
parent
c65d093371
commit
c952fe03ca
1 changed files with 224 additions and 0 deletions
224
discord-bot/events/messageCreate-announcements.js
Normal file
224
discord-bot/events/messageCreate-announcements.js
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
const { createClient } = require("@supabase/supabase-js");
|
||||
const fetch = require("node-fetch");
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
Loading…
Reference in a new issue