Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ bin/
/env.json
userdb.json
/commands
prod.db
logs/forgebot-errors.log
logs/forgebot-io.log
logs/forgebot.log
16 changes: 11 additions & 5 deletions src/main/java/nl/finnt730/Main.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package nl.finnt730;

import java.io.File;
import java.util.EnumSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jsonstructure.DynamicJson;

import haxe.root.JsonStructureLib;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.utils.MemberCachePolicy;
import net.dv8tion.jda.api.utils.cache.CacheFlag;
import nl.finnt730.commands.CommandMigrator;
import nl.finnt730.listeners.CommandListener;
import nl.finnt730.listeners.GnomeBotDevListener;
import nl.finnt730.listeners.PasteListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.EnumSet;
import nl.finnt730.listeners.SelfDestructListener;

public final class Main {
private static final Logger logger = LoggerFactory.getLogger(Main.class);
Expand Down Expand Up @@ -59,6 +63,8 @@ public static void main(String[] args) {
discordLogger.info("Starting Discord bot...");
JDABuilder.createLight(botToken, EnumSet.of(GatewayIntent.GUILD_MESSAGES, GatewayIntent.MESSAGE_CONTENT, GatewayIntent.GUILD_MESSAGE_POLLS, GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGE_REACTIONS))
.addEventListeners(new CommandListener())
.addEventListeners(new GnomeBotDevListener())
.addEventListeners(new SelfDestructListener())
.addEventListeners(new PasteListener())
.enableCache(CacheFlag.ROLE_TAGS)
.setMemberCachePolicy(MemberCachePolicy.ALL) // Would do ONLINE but I don't think that will work if you aren't literally set to Online status.
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/nl/finnt730/commands/CommandCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
public class CommandCache {
private static final Map<String, Command> cache = new HashMap<>();
public static final String DEFAULT_PREFIX = "!";
public static final String HOI4_ESP = "º";//In HOI4 they always use the key next to 1 no matter the layout.
public static final String HOI4_ESP = "\u00BA";//In HOI4 they always use the key next to 1 no matter the layout.
private static final DatabaseManager dbManager = DatabaseManager.getInstance();

// Init builtin commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public void handle(MessageReceivedEvent event, Member invoker, String commandCon
}
} catch (Exception ex) {
event.getChannel().sendMessage("Something went wrong while trying to add aliases. Try again.").queue();
ex.printStackTrace();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ public ReservedCommand() {

@Override
public final boolean canInvoke(Guild guild, Member invoker) {
return invoker.getRoles().stream().anyMatch((role) -> role.isHoisted() || Global.isManager(role));
return invoker.getRoles().stream().anyMatch((role) -> role.isHoisted() || Global.isManager(role) || invoker.isOwner());
}
}
96 changes: 96 additions & 0 deletions src/main/java/nl/finnt730/listeners/GnomeBotDevListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package nl.finnt730.listeners;

import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class GnomeBotDevListener extends ListenerAdapter {
private static final Logger logger = LoggerFactory.getLogger("nl.finnt730.linkconverter");
private static final String GNOMEBOT_DOMAIN = "gnomebot.dev";
private static final String MCLOGS_PATH = "/paste/mclogs/";
private static final String SHIELD_EMOJI = "🛡️";
private static final Emoji SHIELD_EMOJI_OBJ = Emoji.fromUnicode(SHIELD_EMOJI);

private static final Pattern GNOMEBOT_PATTERN = Pattern.compile(
"https?://" + Pattern.quote(GNOMEBOT_DOMAIN) + Pattern.quote(MCLOGS_PATH) + "([a-zA-Z0-9]+)",
Pattern.CASE_INSENSITIVE);
private static final Pattern LOGS_UPLOADED_PATTERN = Pattern
.compile("The logs have been uploaded to `" + Pattern.quote(GNOMEBOT_DOMAIN) + "`");

@Override
public void onMessageReceived(MessageReceivedEvent event) {
try {
if (event.getAuthor().isBot()) {
return;
}

Message message = event.getMessage();
String content = message.getContentRaw();

if (content.contains(GNOMEBOT_DOMAIN)) {
logger.debug("Found gnomebot.dev link in message from user {}", event.getAuthor().getName());
message.addReaction(SHIELD_EMOJI_OBJ).queue();
}
} catch (Exception e) {
logger.error("Error processing message for link conversion setup", e);
}
}

@Override
public void onMessageReactionAdd(MessageReactionAddEvent event) {
try {
if (event.getUser().isBot()) {
return;
}

if (SHIELD_EMOJI.equals(event.getReaction().getEmoji().getName())) {
logger.info("Link conversion reaction triggered by user {} on message {}", event.getUser().getName(),
event.getMessageId());

event.getChannel().retrieveMessageById(event.getMessageId()).queue(message -> {
// Clear all reactions first to prevent duplicate processing
message.clearReactions().queue(v -> {
try {
String content = message.getContentRaw();
final String convertedContent = LOGS_UPLOADED_PATTERN.matcher(convertGnomebotLinks(content))
.replaceAll("The logs have been uploaded to `mclo.gs`");

if (!convertedContent.equals(content)) {
message.reply(convertedContent).mentionRepliedUser(false).queue();
}
} catch (Exception e) {
logger.error("Error processing link conversion reaction", e);
}
});
});
}
} catch (Exception e) {
logger.error("Error handling link conversion reaction", e);
}
}

private String convertGnomebotLinks(String content) {
Matcher matcher = GNOMEBOT_PATTERN.matcher(content);
StringBuffer result = new StringBuffer();

while (matcher.find()) {
String originalLink = matcher.group(0);
String linkId = matcher.group(1);
String mcloLink = "https://mclo.gs/" + linkId;

logger.debug("Converting link: {} -> {}", originalLink, mcloLink);
matcher.appendReplacement(result, mcloLink);
}
matcher.appendTail(result);

return result.toString();
}
}
7 changes: 4 additions & 3 deletions src/main/java/nl/finnt730/listeners/PasteListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public void onMessageReactionAdd(MessageReactionAddEvent event) {
}
}
}
createPaste(attachmentContent, event.getChannel(), fileNames, event.getUserId());
createPaste(attachmentContent, event.getChannel(), fileNames, event.getUserId(),message);
}
} catch (Exception e) {
logger.error("Error processing paste reaction", e);
Expand All @@ -119,7 +119,7 @@ public void onMessageReactionAdd(MessageReactionAddEvent event) {
}

private static void createPaste(List<String> contentList, MessageChannel channel,
List<String> fileNames, String userId) {
List<String> fileNames, String userId, Message message) {
CompletableFuture.runAsync(() -> {
try {
logger.info("Creating paste for user {} with {} files", userId, contentList.size());
Expand Down Expand Up @@ -164,7 +164,7 @@ private static void createPaste(List<String> contentList, MessageChannel channel
}
}

channel.sendMessage(pasteResponse.toString()).queue();
message.reply(pasteResponse.toString()).mentionRepliedUser(false).queue();
logger.info("Paste creation completed for user {}", userId);
} catch (Exception e) {
logger.error("Error in paste creation process", e);
Expand All @@ -174,6 +174,7 @@ private static void createPaste(List<String> contentList, MessageChannel channel

private static boolean isPasteable(Message.Attachment attachment) {
if (attachment.isVideo() || attachment.isImage()) return false;
if(attachment.getFileName().equals("cd_launcherlog")) return true;
return !DENYLISTED_EXTENSIONS.contains(attachment.getFileExtension());
}
}
70 changes: 70 additions & 0 deletions src/main/java/nl/finnt730/listeners/SelfDestructListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package nl.finnt730.listeners;

import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import nl.finnt730.Global;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SelfDestructListener extends ListenerAdapter {
private static final Logger logger = LoggerFactory.getLogger(SelfDestructListener.class);
private static final String TRASH_EMOJI = "🗑️";
private static final Emoji TRASH_EMOJI_OBJ = Emoji.fromUnicode(TRASH_EMOJI);

@Override
public void onMessageReceived(MessageReceivedEvent event) {
try {
// Only process messages from the bot itself
if (!event.getAuthor().isBot() || !event.getJDA().getSelfUser().equals(event.getAuthor())) {
return;
}

Message message = event.getMessage();
logger.debug("Adding self-destruct reaction to message {}", message.getId());
message.addReaction(TRASH_EMOJI_OBJ).queue();
} catch (Exception e) {
logger.error("Error adding self-destruct reaction", e);
}
}

@Override
public void onMessageReactionAdd(MessageReactionAddEvent event) {
try {
// Ignore reactions from bots
if (event.getUser().isBot()) {
return;
}

// Only process trash bin reactions
if (!TRASH_EMOJI.equals(event.getReaction().getEmoji().getName())) {
return;
}

// Check if the reacted message is from our bot
Message message = event.getChannel().retrieveMessageById(event.getMessageId()).complete();
if (!event.getJDA().getSelfUser().equals(message.getAuthor())) {
return;
}

// Check if the reactor has permission to delete
Member reactor = event.getMember();
if (reactor == null)
return;

boolean hasPermission = reactor.getRoles().stream()
.anyMatch(role -> role.isHoisted() || Global.isManager(role) || reactor.isOwner());

if (hasPermission) {
logger.info("Deleting message {} by request of privileged user {}", message.getId(),
event.getUser().getName());
message.delete().queue();
}
} catch (Exception e) {
logger.error("Error processing self-destruct reaction", e);
}
}
}