From 1b0dfa0f47a2f9bc8acd4b96893697460e3539fe Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 17 Jul 2025 10:24:59 +0530 Subject: [PATCH 01/16] Add JOOQ-based data access classes for guilds and messages Introduces GuildDataAccess and MessageDataAccess classes using JOOQ for database operations. Updates pom.xml to include the JOOQ dependency and modifies .gitignore to exclude the .idea directory. These changes provide structured data access for guild and message management, including registration, retrieval, and message encryption. --- .gitignore | 1 + pom.xml | 5 ++ .../papertrail/database/GuildDataAccess.java | 82 +++++++++++++++++++ .../database/MessageDataAccess.java | 65 +++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 src/main/java/org/papertrail/database/GuildDataAccess.java create mode 100644 src/main/java/org/papertrail/database/MessageDataAccess.java diff --git a/.gitignore b/.gitignore index 128ac1af..43376ce4 100644 --- a/.gitignore +++ b/.gitignore @@ -225,3 +225,4 @@ buildNumber.properties # Custom .idea/discord.xml .env +/.idea diff --git a/pom.xml b/pom.xml index 3499f6f8..8f2f9d55 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,11 @@ postgresql 42.7.7 + + org.jooq + jooq + 3.20.5 + org.apache.commons commons-lang3 diff --git a/src/main/java/org/papertrail/database/GuildDataAccess.java b/src/main/java/org/papertrail/database/GuildDataAccess.java new file mode 100644 index 00000000..62faa32e --- /dev/null +++ b/src/main/java/org/papertrail/database/GuildDataAccess.java @@ -0,0 +1,82 @@ +package org.papertrail.database; + +import org.jooq.DSLContext; + +import java.util.List; + +import static org.jooq.impl.DSL.field; +import static org.jooq.impl.DSL.selectOne; +import static org.jooq.impl.DSL.table; + +public class GuildDataAccess { + + private final DSLContext dsl; + + private static final String GUILD_ID_COLUMN = "guild_id"; + private static final String CHANNEL_ID_COLUMN = "channel_id"; + + public GuildDataAccess(DSLContext dsl) { + this.dsl = dsl; + } + + public void registerGuildAndChannel(String guildId, String channelId, String tableName) { + + dsl.insertInto(table(tableName)) + .columns(field(GUILD_ID_COLUMN), field(CHANNEL_ID_COLUMN)) + .values(Long.parseLong(guildId), Long.parseLong(channelId)) + .onConflictDoNothing() + .execute(); + + } + + public List retrieveAllRegisteredGuilds(String tableName) { + + return dsl.select(field(GUILD_ID_COLUMN)) + .from(table(tableName)) + .fetch(r -> String.valueOf(r.get(GUILD_ID_COLUMN))); + + } + + public List retrieveAllRegisteredChannels(String tableName) { + + return dsl.select(field(CHANNEL_ID_COLUMN)) + .from(table(tableName)) + .fetch(r -> String.valueOf(r.get(CHANNEL_ID_COLUMN))); + + } + + public String retrieveRegisteredChannel (String guildId, String tableName) { + + return dsl.select(field(CHANNEL_ID_COLUMN)) + .from(table(tableName)) + .where(field(GUILD_ID_COLUMN).eq(Long.parseLong(guildId))) + .fetchOneInto(String.class); + } + + public boolean isGuildRegistered (String guildId, String tableName) { + + return dsl.fetchExists( + selectOne() + .from(tableName) + .where(field(GUILD_ID_COLUMN).eq(Long.parseLong(guildId))) + ); + + } + + public boolean isChannelRegistered (String channelId, String tableName) { + + return dsl.fetchExists( + selectOne() + .from(tableName) + .where(field(CHANNEL_ID_COLUMN).eq(Long.parseLong(channelId))) + ); + } + + public void unregister (String guildId, String tableName) { + + dsl.deleteFrom(table(tableName)) + .where(field(GUILD_ID_COLUMN).eq(Long.parseLong(guildId))) + .execute(); + } + +} diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java new file mode 100644 index 00000000..93784fd1 --- /dev/null +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -0,0 +1,65 @@ +package org.papertrail.database; + +import org.jooq.DSLContext; +import org.papertrail.utilities.MessageEncryption; + +import java.util.Map; +import java.util.Objects; + +import static org.jooq.impl.DSL.field; +import static org.jooq.impl.DSL.selectOne; +import static org.jooq.impl.DSL.table; + +public class MessageDataAccess { + + private final DSLContext dsl; + + private static final String MESSAGE_ID_COLUMN = "message_id"; + private static final String MESSAGE_CONTENT_COLUMN = "message_content"; + private static final String AUTHOR_ID_COLUMN = "author_id"; + + public MessageDataAccess (DSLContext dsl) { + this.dsl = dsl; + } + + public void logMessage(String messageId, String messageContent, String authorId) { + + dsl.insertInto(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) + .columns(field(MESSAGE_ID_COLUMN), field(MESSAGE_CONTENT_COLUMN), field(AUTHOR_ID_COLUMN)) + .values(Long.parseLong(messageId), MessageEncryption.encrypt(messageContent), Long.parseLong(authorId)) + .onConflictDoNothing() + .execute(); + } + + public Map retrieveAuthorAndMessage (String messageId) { + + return dsl.select(field(AUTHOR_ID_COLUMN), field(MESSAGE_CONTENT_COLUMN)) + .from(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) + .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) + .fetchOne(r -> + Map.of(String.valueOf(r.get(field(AUTHOR_ID_COLUMN))), Objects.requireNonNull(MessageEncryption.decrypt(String.valueOf(r.get(field(MESSAGE_CONTENT_COLUMN))))))); + } + + public boolean messageExists (String messageId) { + + return dsl.fetchExists( + selectOne().from(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) + .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) + ); + } + + public void updateMessage (String messageId, String messageContent) { + + dsl.update(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) + .set(field(MESSAGE_CONTENT_COLUMN), MessageEncryption.encrypt(messageContent)) + .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) + .execute(); + } + + public void deleteMessage (String messageId) { + + dsl.deleteFrom(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) + .where(field(MESSAGE_ID_COLUMN).eq(messageId)) + .execute(); + } +} From dd98756106a2803090942d8b96c2f0c4e6a732cb Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:29:14 +0530 Subject: [PATCH 02/16] Refactor database access to use data access objects Replaces direct SQL operations in DatabaseConnector with dedicated data access classes (GuildDataAccess, MessageDataAccess) using jOOQ DSL. Updates all listeners and related classes to use the new data access methods, improving modularity and maintainability. Adds AuthorAndMessageEntity for structured message retrieval. --- .../papertrail/cleanup/BotKickListener.java | 22 +- .../database/AuthorAndMessageEntity.java | 22 ++ .../database/DatabaseConnector.java | 219 +----------------- .../database/MessageDataAccess.java | 8 +- .../customlisteners/AnnouncementListener.java | 3 +- .../guildlisteners/ServerBoostListener.java | 2 +- .../loglisteners/AuditLogCommandListener.java | 15 +- .../loglisteners/AuditLogListener.java | 2 +- .../GuildMemberJoinAndLeaveListener.java | 4 +- .../MessageLogCommandListener.java | 15 +- .../messagelisteners/MessageLogListener.java | 187 +++++++-------- .../voicelisteners/GuildVoiceListener.java | 2 +- 12 files changed, 154 insertions(+), 347 deletions(-) create mode 100644 src/main/java/org/papertrail/database/AuthorAndMessageEntity.java diff --git a/src/main/java/org/papertrail/cleanup/BotKickListener.java b/src/main/java/org/papertrail/cleanup/BotKickListener.java index ee437900..26ec55cd 100644 --- a/src/main/java/org/papertrail/cleanup/BotKickListener.java +++ b/src/main/java/org/papertrail/cleanup/BotKickListener.java @@ -1,7 +1,5 @@ package org.papertrail.cleanup; -import java.sql.SQLException; - import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; @@ -10,25 +8,27 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; + /* * This class will have methods that unregister the log channels from the database after the bot has been kicked */ public class BotKickListener extends ListenerAdapter { - + private DatabaseConnector dc; - + public BotKickListener(DatabaseConnector dc) { - this.dc=dc; + this.dc = dc; } - + @Override public void onGuildLeave(@NotNull GuildLeaveEvent event) { - Guild leftGuild = event.getGuild(); try { - dc.unregisterGuildAndChannel(leftGuild.getId(), TableNames.AUDIT_LOG_TABLE); - dc.unregisterGuildAndChannel(leftGuild.getId(), TableNames.MESSAGE_LOG_REGISTRATION_TABLE); - } catch (SQLException e) { - Logger.error(e, "Could not auto-unregister guild upon guild leave: "+event.getGuild().getId()+"/"+event.getGuild().getName()); + Guild leftGuild = event.getGuild(); + dc.getGuildDataAccess().unregister(leftGuild.getId(), TableNames.AUDIT_LOG_TABLE); + dc.getGuildDataAccess().unregister(leftGuild.getId(), TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + } catch (Exception e) { + Logger.error(e, "Could not auto-unregister guild upon guild leave: " + event.getGuild().getId() + "/" + + event.getGuild().getName()); } } } diff --git a/src/main/java/org/papertrail/database/AuthorAndMessageEntity.java b/src/main/java/org/papertrail/database/AuthorAndMessageEntity.java new file mode 100644 index 00000000..736c1085 --- /dev/null +++ b/src/main/java/org/papertrail/database/AuthorAndMessageEntity.java @@ -0,0 +1,22 @@ +package org.papertrail.database; + +public class AuthorAndMessageEntity { + + private final String authorId; + private final String messageContent; + + public AuthorAndMessageEntity(String authorId, String messageContent) { + super(); + this.authorId = authorId; + this.messageContent = messageContent; + } + + public String getAuthorId() { + return authorId; + } + + public String getMessageContent() { + return messageContent; + } + +} diff --git a/src/main/java/org/papertrail/database/DatabaseConnector.java b/src/main/java/org/papertrail/database/DatabaseConnector.java index 8dc95eae..d935e020 100644 --- a/src/main/java/org/papertrail/database/DatabaseConnector.java +++ b/src/main/java/org/papertrail/database/DatabaseConnector.java @@ -2,230 +2,31 @@ import java.sql.Connection; import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import org.jooq.DSLContext; +import org.jooq.SQLDialect; +import org.jooq.impl.DSL; import org.papertrail.utilities.EnvConfig; -import org.papertrail.utilities.MessageEncryption; -import org.tinylog.Logger; public class DatabaseConnector { private static final String DB_URL = EnvConfig.get("DATABASEURL"); - private Connection connect; + private final DSLContext dsl; public DatabaseConnector() throws SQLException { - connect = DriverManager.getConnection(DB_URL); - } - - public void registerGuildAndChannel(String guildId, String channelId, String tableName) throws SQLException { - - String sqlStatement = "INSERT INTO "+tableName+" (guild_id, channel_id) VALUES (?, ?)"; - - try(PreparedStatement psmt = connect.prepareStatement(sqlStatement)){ - psmt.setLong(1, Long.parseLong(guildId)); - psmt.setLong(2, Long.parseLong(channelId)); - psmt.executeUpdate(); - } - - } - - public List retrieveAllRegisteredGuilds(String tableName) { - - String sqlStatement = "SELECT guild_id FROM " + tableName; - List guilds = new ArrayList<>(); - - try (PreparedStatement psmt = connect.prepareStatement(sqlStatement); ResultSet rs = psmt.executeQuery()) { - while (rs.next()) { - guilds.add(String.valueOf(rs.getLong(1))); - } - - return guilds; - } catch (SQLException e) { - Logger.error(e, "Could not retrieve registered guilds"); - return Collections.emptyList(); - } + Connection connection = DriverManager.getConnection(DB_URL); + this.dsl = DSL.using(connection, SQLDialect.POSTGRES); } - public List retrieveAllRegisteredChannels(String tableName) { - - String sqlStatement = "SELECT channel_id FROM " + tableName; - List channels = new ArrayList<>(); - - try (PreparedStatement psmt = connect.prepareStatement(sqlStatement); ResultSet rs = psmt.executeQuery()) { - while (rs.next()) { - channels.add(String.valueOf(rs.getLong(1))); - } - - return channels; - } catch (SQLException e) { - Logger.error(e, "Could not retrieve registered channels"); - return Collections.emptyList(); - } - } - - public String retrieveRegisteredChannelId(String guildId, String tableName) { - - String sqlStatement = "SELECT channel_id FROM " + tableName + " WHERE guild_id = ?"; - String channelId = ""; - - try (PreparedStatement psmt = connect.prepareStatement(sqlStatement)) { - psmt.setLong(1, Long.parseLong(guildId)); - - try (ResultSet rs = psmt.executeQuery()) { - - while (rs.next()) { // by configuration, there will always be only one channel id row at a time - // because registering multiple channels is not allowed - channelId = String.valueOf(rs.getLong("channel_id")); - } - } - return channelId; - } catch (SQLException e) { - Logger.error(e, "Could not retrieve registered guild channel id"); - return null; - } - } - /* - * If a guild of the given id is found, will return that id, otherwise null - */ - public String checkGuildRegistration(String guildId, String tableName) { - - String sqlStatement = "SELECT guild_id FROM " + tableName + " WHERE guild_id = ?"; - - try (PreparedStatement psmt = connect.prepareStatement(sqlStatement)) { - psmt.setLong(1, Long.parseLong(guildId)); - - try (ResultSet rs = psmt.executeQuery()) { - - while (rs.next()) { - return String.valueOf(rs.getLong("guild_id")); - - } - } - return null; - } catch (SQLException e) { - Logger.error("Could not retrieve registered guild channel id", e); - return null; - } - } - - /* - * If a channel of the given id is found, will return that id, otherwise null - */ - public String checkChannelRegistration(String channelId, String tableName) { - - String sqlStatement = "SELECT channel_id FROM " + tableName + " WHERE channel_id = ?"; - - try (PreparedStatement psmt = connect.prepareStatement(sqlStatement)) { - psmt.setLong(1, Long.parseLong(channelId)); - - try (ResultSet rs = psmt.executeQuery()) { - while (rs.next()) { - return String.valueOf(rs.getLong("guild_id")); - } - } - return null; - } catch (SQLException e) { - Logger.error("Could not retrieve registered guild channel id", e); - return null; - } + public GuildDataAccess getGuildDataAccess() { + return new GuildDataAccess(dsl); } - - public void unregisterGuildAndChannel(String guildId, String tableName) throws SQLException { - - String sqlStatement = "DELETE FROM "+tableName+" WHERE guild_id = ?"; - - try(PreparedStatement psmt = connect.prepareStatement(sqlStatement)){ - psmt.setLong(1, Long.parseLong(guildId)); - psmt.executeUpdate(); - } - } - - // MESSAGE FUNCTIONS - public void logMessage(String messageId, String messageContent, String authorId, String tableName) throws SQLException { - - String sqlStatement = "INSERT INTO "+tableName+" (message_id, message_content, author_id) VALUES (?, ?, ?)"; - - try(PreparedStatement psmt = connect.prepareStatement(sqlStatement)){ - psmt.setLong(1, Long.parseLong(messageId)); - psmt.setString(2, MessageEncryption.encrypt(messageContent)); - psmt.setLong(3, Long.parseLong(authorId)); - psmt.executeUpdate(); - } - } - - public List retrieveAuthorAndMessage(String messageId, String tableName) { - - String sqlStatement = "SELECT author_id, message_content FROM " + tableName + " WHERE message_id = ?"; - - String messageContent = ""; - String authorId = ""; - - try (PreparedStatement psmt = connect.prepareStatement(sqlStatement)) { - psmt.setLong(1, Long.parseLong(messageId)); - - try (ResultSet rs = psmt.executeQuery()) { - if (rs.next()) { // only one message is logged per row per message id - messageContent = MessageEncryption.decrypt(rs.getString("message_content")); - authorId = String.valueOf(rs.getLong("author_id")); - return List.of(authorId, messageContent); - } - } - return Collections.emptyList(); - } catch (SQLException e) { - Logger.error("Could not retrieve message", e); - e.printStackTrace(); - return Collections.emptyList(); - } - } - /* - * Checks if the message id exists in the database and returns the same if found, else null - */ - public String checkMessageId(String messageId, String tableName) { - - String sqlStatement = "SELECT message_id FROM " + tableName + " WHERE message_id = ?"; - - try (PreparedStatement psmt = connect.prepareStatement(sqlStatement)) { - psmt.setLong(1, Long.parseLong(messageId)); - - try (ResultSet rs = psmt.executeQuery()) { - if (rs.next()) { // only one message is logged per row per message id - return String.valueOf(rs.getLong("message_id")); - } - } - return null; - } catch (SQLException e) { - Logger.error("Could not retrieve message id", e); - e.printStackTrace(); - return null; - } - } - - public void updateMessage(String messageId, String messageContent, String tableName) throws SQLException { - - String sqlStatement = "UPDATE " + tableName + " SET message_content = ? WHERE message_id = ?"; - - try(PreparedStatement psmt = connect.prepareStatement(sqlStatement)){ - psmt.setString(1, MessageEncryption.encrypt(messageContent)); - psmt.setLong(2, Long.parseLong(messageId)); - psmt.executeUpdate(); - } + public MessageDataAccess getMessageDataAccess() { + return new MessageDataAccess(dsl); } - public void deleteMessage(String messageId, String tableName) throws SQLException { - - String sqlStatement = "DELETE FROM "+tableName+" WHERE message_id = ?"; - - try(PreparedStatement psmt = connect.prepareStatement(sqlStatement)){ - psmt.setLong(1, Long.parseLong(messageId)); - psmt.executeUpdate(); - } - } } diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java index 93784fd1..5d940be6 100644 --- a/src/main/java/org/papertrail/database/MessageDataAccess.java +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -3,9 +3,6 @@ import org.jooq.DSLContext; import org.papertrail.utilities.MessageEncryption; -import java.util.Map; -import java.util.Objects; - import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.selectOne; import static org.jooq.impl.DSL.table; @@ -31,13 +28,12 @@ public void logMessage(String messageId, String messageContent, String authorId) .execute(); } - public Map retrieveAuthorAndMessage (String messageId) { + public AuthorAndMessageEntity retrieveAuthorAndMessage (String messageId) { return dsl.select(field(AUTHOR_ID_COLUMN), field(MESSAGE_CONTENT_COLUMN)) .from(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) - .fetchOne(r -> - Map.of(String.valueOf(r.get(field(AUTHOR_ID_COLUMN))), Objects.requireNonNull(MessageEncryption.decrypt(String.valueOf(r.get(field(MESSAGE_CONTENT_COLUMN))))))); + .fetchOne(r -> new AuthorAndMessageEntity(String.valueOf(r.get(field(AUTHOR_ID_COLUMN))), MessageEncryption.decrypt(String.valueOf(r.get(field(MESSAGE_CONTENT_COLUMN)))))); } public boolean messageExists (String messageId) { diff --git a/src/main/java/org/papertrail/listeners/customlisteners/AnnouncementListener.java b/src/main/java/org/papertrail/listeners/customlisteners/AnnouncementListener.java index 7ee5672f..019a2eeb 100644 --- a/src/main/java/org/papertrail/listeners/customlisteners/AnnouncementListener.java +++ b/src/main/java/org/papertrail/listeners/customlisteners/AnnouncementListener.java @@ -35,7 +35,8 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { if(event.getName().equals("announcement")) { - List registeredChannelList = dc.retrieveAllRegisteredChannels(TableNames.AUDIT_LOG_TABLE); + List registeredChannelList = dc.getGuildDataAccess().retrieveAllRegisteredChannels(TableNames.AUDIT_LOG_TABLE); + if(registeredChannelList.isEmpty()) { return; } diff --git a/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java b/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java index 5e81ad1a..3bcc4064 100644 --- a/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java +++ b/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java @@ -27,7 +27,7 @@ public void onGuildMemberUpdateBoostTime(GuildMemberUpdateBoostTimeEvent event) // this will return a non-null text id if a channel was previously registered in the database // server boost logs are mapped to audit log table - String registeredChannelId=dc.retrieveRegisteredChannelId(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + String registeredChannelId=dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); if(registeredChannelId==null ||registeredChannelId.isBlank()) { return; diff --git a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogCommandListener.java b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogCommandListener.java index bcb07ea2..6c456269 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogCommandListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogCommandListener.java @@ -1,7 +1,6 @@ package org.papertrail.listeners.loglisteners; import java.awt.Color; -import java.sql.SQLException; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; @@ -59,7 +58,7 @@ private void setAuditLogging(SlashCommandInteractionEvent event) { String guildId = event.getGuild().getId(); // retrieve the previously registered channel_id associated with the given // guild_id - String registeredChannelId = dc.retrieveRegisteredChannelId(guildId, TableNames.AUDIT_LOG_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.AUDIT_LOG_TABLE); // if there is a registered channel_id in the database, send a warning message // in the channel where the command was called from, stating that a channel has @@ -83,7 +82,7 @@ private void setAuditLogging(SlashCommandInteractionEvent event) { String channelIdToRegister = event.getChannel().asTextChannel().getId(); try { // register the channel_id along with guild_id in the database - dc.registerGuildAndChannel(guildId, channelIdToRegister, TableNames.AUDIT_LOG_TABLE); + dc.getGuildDataAccess().registerGuildAndChannel(guildId, channelIdToRegister, TableNames.AUDIT_LOG_TABLE); EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("πŸ“ Audit Log Configuration"); @@ -93,7 +92,7 @@ private void setAuditLogging(SlashCommandInteractionEvent event) { event.replyEmbeds(mb).setEphemeral(false).queue(); - } catch (SQLException e) { + } catch (Exception e) { EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("πŸ“ Audit Log Configuration"); @@ -118,7 +117,7 @@ private void retrieveAuditLoggingChannel(SlashCommandInteractionEvent event) { String guildId = event.getGuild().getId(); // retrieve the channel_id registered in the database - String registeredChannelId = dc.retrieveRegisteredChannelId(guildId, TableNames.AUDIT_LOG_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.AUDIT_LOG_TABLE); // if there is no channel_id for the given guild_id in the database, then inform // the user of the same, else link the channel that has been registered @@ -166,7 +165,7 @@ private void unsetAuditLogging(SlashCommandInteractionEvent event) { } String guildId = event.getGuild().getId(); - String registeredChannelId = dc.retrieveRegisteredChannelId(guildId, TableNames.AUDIT_LOG_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.AUDIT_LOG_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { @@ -180,7 +179,7 @@ private void unsetAuditLogging(SlashCommandInteractionEvent event) { } else { try { - dc.unregisterGuildAndChannel(guildId, TableNames.AUDIT_LOG_TABLE); + dc.getGuildDataAccess().unregister(guildId, TableNames.AUDIT_LOG_TABLE); EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("πŸ“ Audit Log Configuration"); @@ -190,7 +189,7 @@ private void unsetAuditLogging(SlashCommandInteractionEvent event) { event.replyEmbeds(mb).setEphemeral(false).queue(); - } catch (SQLException e) { + } catch (Exception e) { EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("πŸ“ Audit Log Configuration"); diff --git a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java index 6c02a65b..2d88f199 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java @@ -45,7 +45,7 @@ public AuditLogListener(DatabaseConnector dc) { public void onGuildAuditLogEntryCreate(GuildAuditLogEntryCreateEvent event) { // this will return a non-null text id if a channel was previously registered in the database - String registeredChannelId=dc.retrieveRegisteredChannelId(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + String registeredChannelId=dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); if(registeredChannelId==null ||registeredChannelId.isBlank()) { return; diff --git a/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java b/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java index b34770e9..9f243992 100644 --- a/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java +++ b/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java @@ -29,7 +29,7 @@ public void onGuildMemberJoin(GuildMemberJoinEvent event) { // this will return a non-null text id if a channel was previously registered in // the database // guild member join and leave events are mapped to audit log table - String registeredChannelId = dc.retrieveRegisteredChannelId(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { return; @@ -62,7 +62,7 @@ public void onGuildMemberRemove(GuildMemberRemoveEvent event) { // this will return a non-null text id if a channel was previously registered in // the database - String registeredChannelId = dc.retrieveRegisteredChannelId(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { return; diff --git a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogCommandListener.java b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogCommandListener.java index 3cb11ebe..0a1bb461 100644 --- a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogCommandListener.java +++ b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogCommandListener.java @@ -1,7 +1,6 @@ package org.papertrail.listeners.messagelisteners; import java.awt.Color; -import java.sql.SQLException; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; @@ -61,7 +60,7 @@ private void setMessageLogging(SlashCommandInteractionEvent event) { Guild guild = event.getGuild(); String guildId = guild.getId(); - String registeredChannelId = dc.retrieveRegisteredChannelId(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); if(registeredChannelId!=null && !registeredChannelId.isBlank()) { @@ -79,7 +78,7 @@ private void setMessageLogging(SlashCommandInteractionEvent event) { String channelIdToRegister = event.getChannelId(); try { // register the channel_id along with guild_id in the database - dc.registerGuildAndChannel(guildId, channelIdToRegister, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + dc.getGuildDataAccess().registerGuildAndChannel(guildId, channelIdToRegister, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); eb.addField("βœ… Channel Registration Success","β•°β”ˆβž€"+"All edited and deleted messages will be logged here", false); eb.setColor(Color.GREEN); @@ -89,7 +88,7 @@ private void setMessageLogging(SlashCommandInteractionEvent event) { eb.clearFields(); - } catch (SQLException e) { + } catch (Exception e) { eb.addField("❌ Channel Registration Failure","β•°β”ˆβž€"+"Channel could not be registered", false); eb.setColor(Color.BLACK); @@ -116,7 +115,7 @@ private void retrieveMessageLoggingChannel(SlashCommandInteractionEvent event) { Guild guild = event.getGuild(); String guildId = guild.getId(); - String registeredChannelId = dc.retrieveRegisteredChannelId(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); // if there is no channel_id for the given guild_id in the database, then inform // the user of the same, else link the channel that has been registered if (registeredChannelId == null || registeredChannelId.isBlank()) { @@ -157,7 +156,7 @@ private void unsetMessageLogging(SlashCommandInteractionEvent event) { Guild guild = event.getGuild(); String guildId = guild.getId(); - String registeredChannelId = dc.retrieveRegisteredChannelId(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { eb.addField("ℹ️ Channel Removal", "β•°β”ˆβž€"+"No channel has been registered for message logs", false); @@ -171,7 +170,7 @@ private void unsetMessageLogging(SlashCommandInteractionEvent event) { } else { try { - dc.unregisterGuildAndChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + dc.getGuildDataAccess().unregister(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); eb.addField("βœ… Channel Removal", "β•°β”ˆβž€"+"Channel successfully unset", false); eb.setColor(Color.GREEN); @@ -180,7 +179,7 @@ private void unsetMessageLogging(SlashCommandInteractionEvent event) { event.replyEmbeds(mb).setEphemeral(false).queue(); eb.clearFields(); - } catch (SQLException e) { + } catch (Exception e) { eb.addField("❌ Channel Removal Failure", "β•°β”ˆβž€"+"Channel could not be unset", false); eb.setColor(Color.BLACK); MessageEmbed mb = eb.build(); diff --git a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java index 93f6726e..eff4492f 100644 --- a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java +++ b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java @@ -1,10 +1,8 @@ package org.papertrail.listeners.messagelisteners; import java.awt.Color; -import java.sql.SQLException; import java.time.Instant; -import java.util.List; - +import org.papertrail.database.AuthorAndMessageEntity; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; import org.tinylog.Logger; @@ -40,22 +38,18 @@ public void onMessageReceived(MessageReceivedEvent event) { // get the guild id for which the event was fired String guildId = event.getGuild().getId(); // see if the guild id is registered in the database for logging - String registeredGuildId = dc.checkGuildRegistration(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); // if not registered, exit - if(registeredGuildId==null) { + if(!dc.getGuildDataAccess().isGuildRegistered(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE)) { return; } // else if the registered guild id matches with the event fetched guild id, log the message with its ID and author - if(registeredGuildId.equals(guildId)) { - try { - String messageId = event.getMessageId(); - dc.logMessage(messageId, event.getMessage().getContentRaw(), event.getAuthor().getId(), TableNames.MESSAGE_LOG_CONTENT_TABLE); - } catch (SQLException e) { - Logger.error(e, "Could not log message"); - e.printStackTrace(); - } + try { + String messageId = event.getMessageId(); + dc.getMessageDataAccess().logMessage(messageId, event.getMessage().getContentRaw(), event.getAuthor().getId()); + } catch (Exception e) { + Logger.error(e, "Could not log message"); } } @@ -69,55 +63,52 @@ public void onMessageUpdate(MessageUpdateEvent event) { String guildId = event.getGuild().getId(); - String registeredGuildId = dc.checkGuildRegistration(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); - if(registeredGuildId==null) { + if(!dc.getGuildDataAccess().isGuildRegistered(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE)) { return; } - if(registeredGuildId.equals(guildId)) { - try { - // get the message id of the message which was updated - String messageId = event.getMessageId(); - - // fetch the old message content and its author from the database - List oldAuthorAndMessage = dc.retrieveAuthorAndMessage(messageId, TableNames.MESSAGE_LOG_CONTENT_TABLE); - if(oldAuthorAndMessage==null || oldAuthorAndMessage.isEmpty()) { // would be true only if the unedited message was not logged in the first place - return; - } - // fetch the updated message from the event - String updatedMessage = event.getMessage().getContentRaw(); - - // Ignore events where the message content wasn't edited (e.g., pin, embed resolve, thread creates and updates) - // This is required since MessageUpdateEvent is triggered in case of pins and embed resolves with no change to content - if(updatedMessage.equals(oldAuthorAndMessage.getLast())) { - return; - } - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“ Message Edit Event"); - eb.setDescription("A message sent by "+event.getAuthor().getAsMention()+" has been edited in: "+event.getJumpUrl()); - eb.setColor(Color.YELLOW); - - eb.addField("Old Message", oldAuthorAndMessage.getLast(), false); // get only the message and not the author - eb.addField("New Message", updatedMessage, false); - - eb.setFooter(event.getGuild().getName()); - eb.setTimestamp(Instant.now()); - // update the database with the new message - dc.updateMessage(messageId, updatedMessage, TableNames.MESSAGE_LOG_CONTENT_TABLE); - // the reason this is above the send queue is because in case where the user did not give sufficient permissions to - // the bot, the error responses wouldn't block the update of the message in the database. - - // fetch the channel id from the database - // this channel is where the logs will be sent to - // wrap the embed and send - MessageEmbed mb = eb.build(); - String channelIdToSendTo = dc.retrieveRegisteredChannelId(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); - } catch (SQLException e) { - Logger.error(e, "Could not log updated message"); - e.printStackTrace(); + try { + // get the message id of the message which was updated + String messageId = event.getMessageId(); + + // fetch the old message content and its author from the database + AuthorAndMessageEntity ame = dc.getMessageDataAccess().retrieveAuthorAndMessage(messageId); + if(ame.getAuthorId()==null || ame.getAuthorId().isBlank()) { // would be true only if the unedited message was not logged in the first place + return; + } + // fetch the updated message and its author from the event + String updatedMessage = event.getMessage().getContentRaw(); + + // Ignore events where the message content wasn't edited (e.g., pin, embed resolve, thread creates and updates) + // This is required since MessageUpdateEvent is triggered in case of pins and embed resolves with no change to content + if(updatedMessage.equals(ame.getMessageContent())) { + return; } + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ“ Message Edit Event"); + eb.setDescription("A message sent by "+event.getAuthor().getAsMention()+" has been edited in: "+event.getJumpUrl()); + eb.setColor(Color.YELLOW); + + eb.addField("Old Message", ame.getMessageContent(), false); // get only the message and not the author + eb.addField("New Message", updatedMessage, false); + + eb.setFooter(event.getGuild().getName()); + eb.setTimestamp(Instant.now()); + // update the database with the new message + dc.getMessageDataAccess().updateMessage(messageId, updatedMessage); + // the reason this is above the send queue is because in case where the user did not give sufficient permissions to + // the bot, the error responses wouldn't block the update of the message in the database. + + // fetch the channel id from the database + // this channel is where the logs will be sent to + // wrap the embed and send + MessageEmbed mb = eb.build(); + String channelIdToSendTo = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + } catch (Exception e) { + Logger.error(e, "Could not log updated message"); + e.printStackTrace(); } } @@ -126,51 +117,49 @@ public void onMessageDelete(MessageDeleteEvent event) { String guildId = event.getGuild().getId(); - String registeredGuildId = dc.checkGuildRegistration(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); - if(registeredGuildId==null) { + if(!dc.getGuildDataAccess().isGuildRegistered(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE)) { return; } - if(registeredGuildId.equals(guildId)) { - try { - // get the message id of the message which was deleted - String messageId = event.getMessageId(); - // if the message id does not exist in db, it means the message has not been logged in the first place - if(dc.checkMessageId(messageId, TableNames.MESSAGE_LOG_CONTENT_TABLE)==null) { - return; - } - - // retrieve the channel id where the logs must be sent - String channelIdToSendTo = dc.retrieveRegisteredChannelId(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); - // retrieve the stored message in the database which was deleted - List oldAuthorAndMessage = dc.retrieveAuthorAndMessage(messageId, TableNames.MESSAGE_LOG_CONTENT_TABLE); - - User author = event.getJDA().getUserById(oldAuthorAndMessage.getFirst()); - String mentionableAuthor = (author !=null ? author.getAsMention() : oldAuthorAndMessage.getFirst()); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ—‘οΈ Message Delete Event"); - eb.setDescription("A message sent by "+mentionableAuthor+" has been deleted"); - eb.setColor(Color.RED); - eb.addField("Deleted Message", oldAuthorAndMessage.getLast(), false); - - eb.setFooter(event.getGuild().getName()); - eb.setTimestamp(Instant.now()); - - // delete the message from the database - dc.deleteMessage(messageId, TableNames.MESSAGE_LOG_CONTENT_TABLE); - // the reason this is above the send queue is because in case where the user did not give sufficient permissions to - // the bot, the error responses wouldn't block the deletion in the database. - - // send the fetched deleted message to the logging channel - MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); - - } catch (SQLException e) { - Logger.error(e, "Could not delete message"); - e.printStackTrace(); - + try { + // get the message id of the message which was deleted + String messageId = event.getMessageId(); + + // if the message id does not exist in db, it means the message has not been logged in the first place + if(!dc.getMessageDataAccess().messageExists(messageId)) { + return; } + + // retrieve the channel id where the logs must be sent + String channelIdToSendTo = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + // retrieve the stored message in the database which was deleted + AuthorAndMessageEntity ame = dc.getMessageDataAccess().retrieveAuthorAndMessage(messageId); + + User author = event.getJDA().getUserById(ame.getAuthorId()); + String mentionableAuthor = (author !=null ? author.getAsMention() : ame.getAuthorId()); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ—‘οΈ Message Delete Event"); + eb.setDescription("A message sent by "+mentionableAuthor+" has been deleted"); + eb.setColor(Color.RED); + eb.addField("Deleted Message", ame.getMessageContent(), false); + + eb.setFooter(event.getGuild().getName()); + eb.setTimestamp(Instant.now()); + + // delete the message from the database + dc.getMessageDataAccess().deleteMessage(messageId); + // the reason this is above the send queue is because in case where the user did not give sufficient permissions to + // the bot, the error responses wouldn't block the deletion in the database. + + // send the fetched deleted message to the logging channel + MessageEmbed mb = eb.build(); + event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + + } catch (Exception e) { + Logger.error(e, "Could not delete message"); + e.printStackTrace(); + } } } diff --git a/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java b/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java index 68faeb85..b63268f1 100644 --- a/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java +++ b/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java @@ -27,7 +27,7 @@ public void onGuildVoiceUpdate(GuildVoiceUpdateEvent event) { // this will return a non-null text id if a channel was previously registered in // the database // guild voice events are mapped to audit log table - String registeredChannelId = dc.retrieveRegisteredChannelId(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { return; From dbaa763320f0707441e71a3421cd983bc55f6290 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 17 Jul 2025 11:49:51 +0530 Subject: [PATCH 03/16] Fix message deletion by parsing messageId as Long Updated the deleteMessage method to parse the messageId string to a Long before using it in the where clause. This ensures correct type matching for the MESSAGE_ID_COLUMN in the database. --- src/main/java/org/papertrail/database/MessageDataAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java index 5d940be6..f39596ad 100644 --- a/src/main/java/org/papertrail/database/MessageDataAccess.java +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -55,7 +55,7 @@ public void updateMessage (String messageId, String messageContent) { public void deleteMessage (String messageId) { dsl.deleteFrom(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) - .where(field(MESSAGE_ID_COLUMN).eq(messageId)) + .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) .execute(); } } From 906b10a5ecdc16a0bc7cb4a493b658aee9acf85c Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 17 Jul 2025 13:01:55 +0530 Subject: [PATCH 04/16] Make database operations async and improve error handling Refactored MessageDataAccess to use asynchronous database operations with executeAsync and added error logging using Tinylog. Updated MessageLogListener to handle null AuthorAndMessageEntity and removed unnecessary printStackTrace calls for cleaner error handling. --- .../database/MessageDataAccess.java | 19 ++++++++++++++++--- .../messagelisteners/MessageLogListener.java | 7 +++---- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java index f39596ad..15d272b8 100644 --- a/src/main/java/org/papertrail/database/MessageDataAccess.java +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -2,6 +2,7 @@ import org.jooq.DSLContext; import org.papertrail.utilities.MessageEncryption; +import org.tinylog.Logger; import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.selectOne; @@ -25,7 +26,11 @@ public void logMessage(String messageId, String messageContent, String authorId) .columns(field(MESSAGE_ID_COLUMN), field(MESSAGE_CONTENT_COLUMN), field(AUTHOR_ID_COLUMN)) .values(Long.parseLong(messageId), MessageEncryption.encrypt(messageContent), Long.parseLong(authorId)) .onConflictDoNothing() - .execute(); + .executeAsync() + .exceptionally(e -> { + Logger.error(e, "Error logging message to the database. MessageID: {} AuthorID: {}",messageId, authorId); + return null; + }); } public AuthorAndMessageEntity retrieveAuthorAndMessage (String messageId) { @@ -49,13 +54,21 @@ public void updateMessage (String messageId, String messageContent) { dsl.update(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) .set(field(MESSAGE_CONTENT_COLUMN), MessageEncryption.encrypt(messageContent)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) - .execute(); + .executeAsync() + .exceptionally(e -> { + Logger.error(e, "Error updating message in the database. MessageID: "+messageId); + return null; + }); } public void deleteMessage (String messageId) { dsl.deleteFrom(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) - .execute(); + .executeAsync() + .exceptionally(e -> { + Logger.error(e, "Error deleting message from database. MessageID: "+messageId); + return null; + }); } } diff --git a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java index eff4492f..6466ef0e 100644 --- a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java +++ b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java @@ -73,7 +73,7 @@ public void onMessageUpdate(MessageUpdateEvent event) { // fetch the old message content and its author from the database AuthorAndMessageEntity ame = dc.getMessageDataAccess().retrieveAuthorAndMessage(messageId); - if(ame.getAuthorId()==null || ame.getAuthorId().isBlank()) { // would be true only if the unedited message was not logged in the first place + if(ame==null || ame.getAuthorId()==null || ame.getAuthorId().isBlank()) { // would be true only if the unedited message was not logged in the first place return; } // fetch the updated message and its author from the event @@ -108,7 +108,7 @@ public void onMessageUpdate(MessageUpdateEvent event) { event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); } catch (Exception e) { Logger.error(e, "Could not log updated message"); - e.printStackTrace(); + } } @@ -154,11 +154,10 @@ public void onMessageDelete(MessageDeleteEvent event) { // send the fetched deleted message to the logging channel MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); } catch (Exception e) { Logger.error(e, "Could not delete message"); - e.printStackTrace(); } } From e885605c5ebd38cc76e5b4f066c56b2569adcf77 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 17 Jul 2025 13:12:28 +0530 Subject: [PATCH 05/16] Update MessageLogListener.java --- .../listeners/messagelisteners/MessageLogListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java index 6466ef0e..577198e0 100644 --- a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java +++ b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java @@ -150,7 +150,7 @@ public void onMessageDelete(MessageDeleteEvent event) { // delete the message from the database dc.getMessageDataAccess().deleteMessage(messageId); // the reason this is above the send queue is because in case where the user did not give sufficient permissions to - // the bot, the error responses wouldn't block the deletion in the database. + // the bot, (such as no send message permissions) the exceptions wouldn't block the deletion in the database. // send the fetched deleted message to the logging channel MessageEmbed mb = eb.build(); From c17f52a67ecfccc1d6e54059c9d5226f150010ad Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 17 Jul 2025 14:50:05 +0530 Subject: [PATCH 06/16] Add HikariCP connection pooling Replaces direct JDBC connections with HikariCP --- pom.xml | 5 +++ .../database/DatabaseConnector.java | 35 +++++++++++++++---- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 8f2f9d55..c8df87e9 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,11 @@ dotenv-java 3.2.0 + + com.zaxxer + HikariCP + 6.3.0 + org.postgresql postgresql diff --git a/src/main/java/org/papertrail/database/DatabaseConnector.java b/src/main/java/org/papertrail/database/DatabaseConnector.java index d935e020..577021ed 100644 --- a/src/main/java/org/papertrail/database/DatabaseConnector.java +++ b/src/main/java/org/papertrail/database/DatabaseConnector.java @@ -1,23 +1,24 @@ package org.papertrail.database; -import java.sql.Connection; -import java.sql.DriverManager; import java.sql.SQLException; import org.jooq.DSLContext; import org.jooq.SQLDialect; import org.jooq.impl.DSL; import org.papertrail.utilities.EnvConfig; +import org.tinylog.Logger; + +import com.zaxxer.hikari.HikariDataSource; public class DatabaseConnector { private static final String DB_URL = EnvConfig.get("DATABASEURL"); - + private static HikariDataSource dataSource; private final DSLContext dsl; public DatabaseConnector() throws SQLException { - Connection connection = DriverManager.getConnection(DB_URL); - this.dsl = DSL.using(connection, SQLDialect.POSTGRES); + initializeDataSource(); + this.dsl = DSL.using(dataSource, SQLDialect.POSTGRES); } public GuildDataAccess getGuildDataAccess() { @@ -27,6 +28,26 @@ public GuildDataAccess getGuildDataAccess() { public MessageDataAccess getMessageDataAccess() { return new MessageDataAccess(dsl); } - - + + private static synchronized void initializeDataSource() { + + if (dataSource == null) { + dataSource = new HikariDataSource(); + dataSource.setJdbcUrl(DB_URL); + dataSource.setMaximumPoolSize(20); // Adjust as needed + dataSource.setMinimumIdle(2); // Adjust as needed + dataSource.setConnectionTimeout(30000); // 30 seconds + dataSource.setIdleTimeout(600000); // 10 minutes + dataSource.setMaxLifetime(1800000); // 30 minutes + dataSource.setPoolName("PaperTrailPool"); + } + // Ensure the data source is closed on shutdown + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + if (dataSource != null && !dataSource.isClosed()) { + dataSource.close(); + Logger.info("Database connection pool closed."); + } + })); + } + } From 544095d4e50e3563d5131976ad7da7489c512617 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Fri, 18 Jul 2025 12:40:20 +0530 Subject: [PATCH 07/16] Update to JDK 24 and switch to synchronous DB operations Switched to JDK24 from 21. Refactored MessageDataAccess to use synchronous database operations instead of async --- Dockerfile | 6 +++--- pom.xml | 4 ++-- .../database/MessageDataAccess.java | 19 +++---------------- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/Dockerfile b/Dockerfile index f19c3903..1b7b117f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Importing JDK and copying required files -FROM openjdk:21-jdk AS build +FROM openjdk:24-jdk AS build WORKDIR /app # Copy Maven wrapper @@ -16,8 +16,8 @@ COPY src ./src RUN ./mvnw clean package -DskipTests -# Stage 2: Create the final Docker image using OpenJDK 21 -FROM openjdk:21-jdk +# Stage 2: Create the final Docker image using OpenJDK 24 +FROM openjdk:24-jdk WORKDIR /app VOLUME /tmp diff --git a/pom.xml b/pom.xml index c8df87e9..2cd1cf12 100644 --- a/pom.xml +++ b/pom.xml @@ -8,8 +8,8 @@ UTF-8 UTF-8 - 21 - 21 + 24 + 24 diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java index 15d272b8..f39596ad 100644 --- a/src/main/java/org/papertrail/database/MessageDataAccess.java +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -2,7 +2,6 @@ import org.jooq.DSLContext; import org.papertrail.utilities.MessageEncryption; -import org.tinylog.Logger; import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.selectOne; @@ -26,11 +25,7 @@ public void logMessage(String messageId, String messageContent, String authorId) .columns(field(MESSAGE_ID_COLUMN), field(MESSAGE_CONTENT_COLUMN), field(AUTHOR_ID_COLUMN)) .values(Long.parseLong(messageId), MessageEncryption.encrypt(messageContent), Long.parseLong(authorId)) .onConflictDoNothing() - .executeAsync() - .exceptionally(e -> { - Logger.error(e, "Error logging message to the database. MessageID: {} AuthorID: {}",messageId, authorId); - return null; - }); + .execute(); } public AuthorAndMessageEntity retrieveAuthorAndMessage (String messageId) { @@ -54,21 +49,13 @@ public void updateMessage (String messageId, String messageContent) { dsl.update(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) .set(field(MESSAGE_CONTENT_COLUMN), MessageEncryption.encrypt(messageContent)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) - .executeAsync() - .exceptionally(e -> { - Logger.error(e, "Error updating message in the database. MessageID: "+messageId); - return null; - }); + .execute(); } public void deleteMessage (String messageId) { dsl.deleteFrom(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) - .executeAsync() - .exceptionally(e -> { - Logger.error(e, "Error deleting message from database. MessageID: "+messageId); - return null; - }); + .execute(); } } From c9ed792d6c952498166b113b96ba95f3585b20e5 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Fri, 18 Jul 2025 12:54:44 +0530 Subject: [PATCH 08/16] Revert "Update to JDK 24 and switch to synchronous DB operations" This reverts commit 544095d4e50e3563d5131976ad7da7489c512617. --- Dockerfile | 6 +++--- pom.xml | 4 ++-- .../database/MessageDataAccess.java | 19 ++++++++++++++++--- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1b7b117f..f19c3903 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Importing JDK and copying required files -FROM openjdk:24-jdk AS build +FROM openjdk:21-jdk AS build WORKDIR /app # Copy Maven wrapper @@ -16,8 +16,8 @@ COPY src ./src RUN ./mvnw clean package -DskipTests -# Stage 2: Create the final Docker image using OpenJDK 24 -FROM openjdk:24-jdk +# Stage 2: Create the final Docker image using OpenJDK 21 +FROM openjdk:21-jdk WORKDIR /app VOLUME /tmp diff --git a/pom.xml b/pom.xml index 2cd1cf12..c8df87e9 100644 --- a/pom.xml +++ b/pom.xml @@ -8,8 +8,8 @@ UTF-8 UTF-8 - 24 - 24 + 21 + 21 diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java index f39596ad..15d272b8 100644 --- a/src/main/java/org/papertrail/database/MessageDataAccess.java +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -2,6 +2,7 @@ import org.jooq.DSLContext; import org.papertrail.utilities.MessageEncryption; +import org.tinylog.Logger; import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.selectOne; @@ -25,7 +26,11 @@ public void logMessage(String messageId, String messageContent, String authorId) .columns(field(MESSAGE_ID_COLUMN), field(MESSAGE_CONTENT_COLUMN), field(AUTHOR_ID_COLUMN)) .values(Long.parseLong(messageId), MessageEncryption.encrypt(messageContent), Long.parseLong(authorId)) .onConflictDoNothing() - .execute(); + .executeAsync() + .exceptionally(e -> { + Logger.error(e, "Error logging message to the database. MessageID: {} AuthorID: {}",messageId, authorId); + return null; + }); } public AuthorAndMessageEntity retrieveAuthorAndMessage (String messageId) { @@ -49,13 +54,21 @@ public void updateMessage (String messageId, String messageContent) { dsl.update(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) .set(field(MESSAGE_CONTENT_COLUMN), MessageEncryption.encrypt(messageContent)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) - .execute(); + .executeAsync() + .exceptionally(e -> { + Logger.error(e, "Error updating message in the database. MessageID: "+messageId); + return null; + }); } public void deleteMessage (String messageId) { dsl.deleteFrom(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) - .execute(); + .executeAsync() + .exceptionally(e -> { + Logger.error(e, "Error deleting message from database. MessageID: "+messageId); + return null; + }); } } From 153037ce924f5c8e5c1b535b14fec764cd0e7e86 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:08:31 +0530 Subject: [PATCH 09/16] Refactor message logging to use synchronous DB ops Replaces asynchronous database operations with synchronous calls in MessageDataAccess, removing Tinylog error handling. In MessageLogListener, introduces a virtual thread pool to offload database operations and removes try-catch blocks and logging --- .../database/MessageDataAccess.java | 19 +---- .../messagelisteners/MessageLogListener.java | 85 +++++++++---------- 2 files changed, 43 insertions(+), 61 deletions(-) diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java index 15d272b8..f39596ad 100644 --- a/src/main/java/org/papertrail/database/MessageDataAccess.java +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -2,7 +2,6 @@ import org.jooq.DSLContext; import org.papertrail.utilities.MessageEncryption; -import org.tinylog.Logger; import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.selectOne; @@ -26,11 +25,7 @@ public void logMessage(String messageId, String messageContent, String authorId) .columns(field(MESSAGE_ID_COLUMN), field(MESSAGE_CONTENT_COLUMN), field(AUTHOR_ID_COLUMN)) .values(Long.parseLong(messageId), MessageEncryption.encrypt(messageContent), Long.parseLong(authorId)) .onConflictDoNothing() - .executeAsync() - .exceptionally(e -> { - Logger.error(e, "Error logging message to the database. MessageID: {} AuthorID: {}",messageId, authorId); - return null; - }); + .execute(); } public AuthorAndMessageEntity retrieveAuthorAndMessage (String messageId) { @@ -54,21 +49,13 @@ public void updateMessage (String messageId, String messageContent) { dsl.update(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) .set(field(MESSAGE_CONTENT_COLUMN), MessageEncryption.encrypt(messageContent)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) - .executeAsync() - .exceptionally(e -> { - Logger.error(e, "Error updating message in the database. MessageID: "+messageId); - return null; - }); + .execute(); } public void deleteMessage (String messageId) { dsl.deleteFrom(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) - .executeAsync() - .exceptionally(e -> { - Logger.error(e, "Error deleting message from database. MessageID: "+messageId); - return null; - }); + .execute(); } } diff --git a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java index 577198e0..dd49c13c 100644 --- a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java +++ b/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java @@ -2,10 +2,13 @@ import java.awt.Color; import java.time.Instant; +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + import org.papertrail.database.AuthorAndMessageEntity; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; -import org.tinylog.Logger; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; @@ -16,8 +19,10 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter; public class MessageLogListener extends ListenerAdapter { - - private DatabaseConnector dc; + + private final Executor vThreadPool = Executors.newVirtualThreadPerTaskExecutor(); + + private final DatabaseConnector dc; public MessageLogListener(DatabaseConnector dc) { this.dc = dc; @@ -25,7 +30,7 @@ public MessageLogListener(DatabaseConnector dc) { @Override public void onMessageReceived(MessageReceivedEvent event) { - + // if the author is a bot or system, don't log if(event.getAuthor().isBot() || event.getAuthor().isSystem()) { return; @@ -34,23 +39,22 @@ public void onMessageReceived(MessageReceivedEvent event) { if(event.getMessage().getContentRaw().isEmpty()) { return; } - + // get the guild id for which the event was fired String guildId = event.getGuild().getId(); // see if the guild id is registered in the database for logging - + // if not registered, exit if(!dc.getGuildDataAccess().isGuildRegistered(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE)) { return; } - + // else if the registered guild id matches with the event fetched guild id, log the message with its ID and author - try { - String messageId = event.getMessageId(); - dc.getMessageDataAccess().logMessage(messageId, event.getMessage().getContentRaw(), event.getAuthor().getId()); - } catch (Exception e) { - Logger.error(e, "Could not log message"); - } + vThreadPool.execute(()-> + dc.getMessageDataAccess().logMessage(event.getMessageId(), event.getMessage().getContentRaw(), event.getAuthor().getId()) + ); + + } @Override @@ -60,56 +64,51 @@ public void onMessageUpdate(MessageUpdateEvent event) { return; } - String guildId = event.getGuild().getId(); - if(!dc.getGuildDataAccess().isGuildRegistered(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE)) { return; } - try { + vThreadPool.execute(()->{ // get the message id of the message which was updated String messageId = event.getMessageId(); - + // fetch the old message content and its author from the database AuthorAndMessageEntity ame = dc.getMessageDataAccess().retrieveAuthorAndMessage(messageId); if(ame==null || ame.getAuthorId()==null || ame.getAuthorId().isBlank()) { // would be true only if the unedited message was not logged in the first place return; } - // fetch the updated message and its author from the event - String updatedMessage = event.getMessage().getContentRaw(); - + // fetch the updated message and its author from the event + String updatedMessage = event.getMessage().getContentRaw(); + // Ignore events where the message content wasn't edited (e.g., pin, embed resolve, thread creates and updates) // This is required since MessageUpdateEvent is triggered in case of pins and embed resolves with no change to content if(updatedMessage.equals(ame.getMessageContent())) { return; } - + EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("πŸ“ Message Edit Event"); eb.setDescription("A message sent by "+event.getAuthor().getAsMention()+" has been edited in: "+event.getJumpUrl()); eb.setColor(Color.YELLOW); - + eb.addField("Old Message", ame.getMessageContent(), false); // get only the message and not the author eb.addField("New Message", updatedMessage, false); - + eb.setFooter(event.getGuild().getName()); eb.setTimestamp(Instant.now()); // update the database with the new message dc.getMessageDataAccess().updateMessage(messageId, updatedMessage); // the reason this is above the send queue is because in case where the user did not give sufficient permissions to - // the bot, the error responses wouldn't block the update of the message in the database. - + // the bot, the error responses wouldn't block the update of the message in the database. + // fetch the channel id from the database // this channel is where the logs will be sent to // wrap the embed and send MessageEmbed mb = eb.build(); String channelIdToSendTo = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); - } catch (Exception e) { - Logger.error(e, "Could not log updated message"); - - } + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); + }); } @Override @@ -121,44 +120,40 @@ public void onMessageDelete(MessageDeleteEvent event) { return; } - try { + vThreadPool.execute(()-> { // get the message id of the message which was deleted String messageId = event.getMessageId(); - + // if the message id does not exist in db, it means the message has not been logged in the first place if(!dc.getMessageDataAccess().messageExists(messageId)) { return; } - + // retrieve the channel id where the logs must be sent String channelIdToSendTo = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); // retrieve the stored message in the database which was deleted AuthorAndMessageEntity ame = dc.getMessageDataAccess().retrieveAuthorAndMessage(messageId); - + User author = event.getJDA().getUserById(ame.getAuthorId()); String mentionableAuthor = (author !=null ? author.getAsMention() : ame.getAuthorId()); - + EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("πŸ—‘οΈ Message Delete Event"); eb.setDescription("A message sent by "+mentionableAuthor+" has been deleted"); eb.setColor(Color.RED); eb.addField("Deleted Message", ame.getMessageContent(), false); - + eb.setFooter(event.getGuild().getName()); eb.setTimestamp(Instant.now()); - - // delete the message from the database + + // delete the message from the database dc.getMessageDataAccess().deleteMessage(messageId); // the reason this is above the send queue is because in case where the user did not give sufficient permissions to // the bot, (such as no send message permissions) the exceptions wouldn't block the deletion in the database. - + // send the fetched deleted message to the logging channel MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); - - } catch (Exception e) { - Logger.error(e, "Could not delete message"); - - } + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); + }); } } From 4dfe13c2348ac9a2f9dbbfe179631f1310331282 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Fri, 18 Jul 2025 13:23:53 +0530 Subject: [PATCH 10/16] Refactor listener package structure and imports Moved and renamed several listener classes to better organize them under 'commandlisteners' and 'loglisteners' packages. Updated package-info files and adjusted all relevant imports in FireRun.java to reflect the new structure. This improves code organization and clarity by grouping listeners according to their responsibilities. --- .../AnnouncementCommandListener.java} | 6 +-- .../AuditLogSetupCommandListener.java} | 6 +-- .../BotInfoCommandListener.java} | 4 +- .../BotSetupCommandListener.java} | 4 +- .../MessageLogSetupCommandListener.java} | 6 +-- ...quiredPermissionCheckCommandListener.java} | 4 +- .../ServerStatCommandListener.java} | 4 +- .../commandlisteners/package-info.java | 4 ++ .../customlisteners/package-info.java | 4 -- .../MessageLogListener.java | 2 +- .../listeners/loglisteners/package-info.java | 2 +- .../messagelisteners/package-info.java | 4 -- .../java/org/papertrail/main/FireRun.java | 49 ++++++++++--------- 13 files changed, 50 insertions(+), 49 deletions(-) rename src/main/java/org/papertrail/listeners/{customlisteners/AnnouncementListener.java => commandlisteners/AnnouncementCommandListener.java} (93%) rename src/main/java/org/papertrail/listeners/{loglisteners/AuditLogCommandListener.java => commandlisteners/AuditLogSetupCommandListener.java} (97%) rename src/main/java/org/papertrail/listeners/{customlisteners/BotInfoListener.java => commandlisteners/BotInfoCommandListener.java} (92%) rename src/main/java/org/papertrail/listeners/{customlisteners/BotSetupListener.java => commandlisteners/BotSetupCommandListener.java} (96%) rename src/main/java/org/papertrail/listeners/{messagelisteners/MessageLogCommandListener.java => commandlisteners/MessageLogSetupCommandListener.java} (97%) rename src/main/java/org/papertrail/listeners/{customlisteners/RequiredPermissionCheckListener.java => commandlisteners/RequiredPermissionCheckCommandListener.java} (95%) rename src/main/java/org/papertrail/listeners/{customlisteners/ServerStatListener.java => commandlisteners/ServerStatCommandListener.java} (96%) create mode 100644 src/main/java/org/papertrail/listeners/commandlisteners/package-info.java delete mode 100644 src/main/java/org/papertrail/listeners/customlisteners/package-info.java rename src/main/java/org/papertrail/listeners/{messagelisteners => loglisteners}/MessageLogListener.java (99%) delete mode 100644 src/main/java/org/papertrail/listeners/messagelisteners/package-info.java diff --git a/src/main/java/org/papertrail/listeners/customlisteners/AnnouncementListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java similarity index 93% rename from src/main/java/org/papertrail/listeners/customlisteners/AnnouncementListener.java rename to src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java index 019a2eeb..6b1e6694 100644 --- a/src/main/java/org/papertrail/listeners/customlisteners/AnnouncementListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java @@ -1,4 +1,4 @@ -package org.papertrail.listeners.customlisteners; +package org.papertrail.listeners.commandlisteners; import java.awt.Color; import java.time.Instant; @@ -17,11 +17,11 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.interactions.commands.OptionMapping; -public class AnnouncementListener extends ListenerAdapter { +public class AnnouncementCommandListener extends ListenerAdapter { private final DatabaseConnector dc; - public AnnouncementListener(DatabaseConnector dc) { + public AnnouncementCommandListener(DatabaseConnector dc) { this.dc = dc; } diff --git a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java similarity index 97% rename from src/main/java/org/papertrail/listeners/loglisteners/AuditLogCommandListener.java rename to src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java index 6c456269..972ea2eb 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java @@ -1,4 +1,4 @@ -package org.papertrail.listeners.loglisteners; +package org.papertrail.listeners.commandlisteners; import java.awt.Color; @@ -14,12 +14,12 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -public class AuditLogCommandListener extends ListenerAdapter { +public class AuditLogSetupCommandListener extends ListenerAdapter { private DatabaseConnector dc; - public AuditLogCommandListener(DatabaseConnector dc) { + public AuditLogSetupCommandListener(DatabaseConnector dc) { this.dc = dc; } diff --git a/src/main/java/org/papertrail/listeners/customlisteners/BotInfoListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/BotInfoCommandListener.java similarity index 92% rename from src/main/java/org/papertrail/listeners/customlisteners/BotInfoListener.java rename to src/main/java/org/papertrail/listeners/commandlisteners/BotInfoCommandListener.java index e5e2aaa2..0829a6e8 100644 --- a/src/main/java/org/papertrail/listeners/customlisteners/BotInfoListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/BotInfoCommandListener.java @@ -1,4 +1,4 @@ -package org.papertrail.listeners.customlisteners; +package org.papertrail.listeners.commandlisteners; import java.awt.Color; import java.time.Instant; @@ -11,7 +11,7 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -public class BotInfoListener extends ListenerAdapter { +public class BotInfoCommandListener extends ListenerAdapter { @Override public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { diff --git a/src/main/java/org/papertrail/listeners/customlisteners/BotSetupListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/BotSetupCommandListener.java similarity index 96% rename from src/main/java/org/papertrail/listeners/customlisteners/BotSetupListener.java rename to src/main/java/org/papertrail/listeners/commandlisteners/BotSetupCommandListener.java index 7a50786f..99226ae4 100644 --- a/src/main/java/org/papertrail/listeners/customlisteners/BotSetupListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/BotSetupCommandListener.java @@ -1,4 +1,4 @@ -package org.papertrail.listeners.customlisteners; +package org.papertrail.listeners.commandlisteners; import java.awt.Color; import java.time.Instant; @@ -10,7 +10,7 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -public class BotSetupListener extends ListenerAdapter { +public class BotSetupCommandListener extends ListenerAdapter { @Override public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { diff --git a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java similarity index 97% rename from src/main/java/org/papertrail/listeners/messagelisteners/MessageLogCommandListener.java rename to src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java index 0a1bb461..8cd73f43 100644 --- a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java @@ -1,4 +1,4 @@ -package org.papertrail.listeners.messagelisteners; +package org.papertrail.listeners.commandlisteners; import java.awt.Color; @@ -15,12 +15,12 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -public class MessageLogCommandListener extends ListenerAdapter { +public class MessageLogSetupCommandListener extends ListenerAdapter { private DatabaseConnector dc; private final EmbedBuilder eb = new EmbedBuilder(); - public MessageLogCommandListener(DatabaseConnector dc) { + public MessageLogSetupCommandListener(DatabaseConnector dc) { this.dc = dc; eb.setTitle("πŸ“ Message Log Configuration"); eb.setColor(Color.CYAN); diff --git a/src/main/java/org/papertrail/listeners/customlisteners/RequiredPermissionCheckListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java similarity index 95% rename from src/main/java/org/papertrail/listeners/customlisteners/RequiredPermissionCheckListener.java rename to src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java index 7b7c799e..a7a81a0c 100644 --- a/src/main/java/org/papertrail/listeners/customlisteners/RequiredPermissionCheckListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java @@ -1,4 +1,4 @@ -package org.papertrail.listeners.customlisteners; +package org.papertrail.listeners.commandlisteners; import java.awt.Color; import java.util.EnumMap; @@ -15,7 +15,7 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -public class RequiredPermissionCheckListener extends ListenerAdapter { +public class RequiredPermissionCheckCommandListener extends ListenerAdapter { @Override public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { diff --git a/src/main/java/org/papertrail/listeners/customlisteners/ServerStatListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/ServerStatCommandListener.java similarity index 96% rename from src/main/java/org/papertrail/listeners/customlisteners/ServerStatListener.java rename to src/main/java/org/papertrail/listeners/commandlisteners/ServerStatCommandListener.java index b8a1f5c3..5fb7c6fb 100644 --- a/src/main/java/org/papertrail/listeners/customlisteners/ServerStatListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/ServerStatCommandListener.java @@ -1,4 +1,4 @@ -package org.papertrail.listeners.customlisteners; +package org.papertrail.listeners.commandlisteners; import java.awt.Color; import java.time.Instant; @@ -14,7 +14,7 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -public class ServerStatListener extends ListenerAdapter{ +public class ServerStatCommandListener extends ListenerAdapter{ @Override public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/package-info.java b/src/main/java/org/papertrail/listeners/commandlisteners/package-info.java new file mode 100644 index 00000000..dd37ae86 --- /dev/null +++ b/src/main/java/org/papertrail/listeners/commandlisteners/package-info.java @@ -0,0 +1,4 @@ +/** + * This package contains classes that listen for slash commands + */ +package org.papertrail.listeners.commandlisteners; \ No newline at end of file diff --git a/src/main/java/org/papertrail/listeners/customlisteners/package-info.java b/src/main/java/org/papertrail/listeners/customlisteners/package-info.java deleted file mode 100644 index f650e385..00000000 --- a/src/main/java/org/papertrail/listeners/customlisteners/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/* - * This will include Custom Listeners that may or may not depend on a specific or generic event - */ -package org.papertrail.listeners.customlisteners; \ No newline at end of file diff --git a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java similarity index 99% rename from src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java rename to src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java index dd49c13c..4b0ba954 100644 --- a/src/main/java/org/papertrail/listeners/messagelisteners/MessageLogListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java @@ -1,4 +1,4 @@ -package org.papertrail.listeners.messagelisteners; +package org.papertrail.listeners.loglisteners; import java.awt.Color; import java.time.Instant; diff --git a/src/main/java/org/papertrail/listeners/loglisteners/package-info.java b/src/main/java/org/papertrail/listeners/loglisteners/package-info.java index b184ad6c..209ac0be 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/package-info.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/package-info.java @@ -1,4 +1,4 @@ /** - * This package contains Classes and Methods that detect and parse audit log activities + * This package contains Classes and Methods that detect and parse audit and message log activities */ package org.papertrail.listeners.loglisteners; \ No newline at end of file diff --git a/src/main/java/org/papertrail/listeners/messagelisteners/package-info.java b/src/main/java/org/papertrail/listeners/messagelisteners/package-info.java deleted file mode 100644 index ff3f1938..00000000 --- a/src/main/java/org/papertrail/listeners/messagelisteners/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/* - * Groups listeners related to message activities - */ -package org.papertrail.listeners.messagelisteners; \ No newline at end of file diff --git a/src/main/java/org/papertrail/main/FireRun.java b/src/main/java/org/papertrail/main/FireRun.java index e1e8d0a1..2f6d47d2 100644 --- a/src/main/java/org/papertrail/main/FireRun.java +++ b/src/main/java/org/papertrail/main/FireRun.java @@ -5,20 +5,21 @@ import java.security.Security; import java.sql.SQLException; +import net.dv8tion.jda.api.sharding.ShardManager; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.papertrail.cleanup.BotKickListener; import org.papertrail.database.DatabaseConnector; -import org.papertrail.listeners.customlisteners.AnnouncementListener; -import org.papertrail.listeners.customlisteners.BotInfoListener; -import org.papertrail.listeners.customlisteners.ServerStatListener; -import org.papertrail.listeners.customlisteners.BotSetupListener; -import org.papertrail.listeners.customlisteners.RequiredPermissionCheckListener; +import org.papertrail.listeners.commandlisteners.AnnouncementCommandListener; +import org.papertrail.listeners.commandlisteners.BotInfoCommandListener; +import org.papertrail.listeners.commandlisteners.ServerStatCommandListener; +import org.papertrail.listeners.commandlisteners.BotSetupCommandListener; +import org.papertrail.listeners.commandlisteners.RequiredPermissionCheckCommandListener; import org.papertrail.listeners.guildlisteners.ServerBoostListener; import org.papertrail.listeners.loglisteners.AuditLogListener; -import org.papertrail.listeners.loglisteners.AuditLogCommandListener; +import org.papertrail.listeners.commandlisteners.AuditLogSetupCommandListener; import org.papertrail.listeners.memberlisteners.GuildMemberJoinAndLeaveListener; -import org.papertrail.listeners.messagelisteners.MessageLogCommandListener; -import org.papertrail.listeners.messagelisteners.MessageLogListener; +import org.papertrail.listeners.commandlisteners.MessageLogSetupCommandListener; +import org.papertrail.listeners.loglisteners.MessageLogListener; import org.papertrail.listeners.voicelisteners.GuildVoiceListener; import org.tinylog.Logger; @@ -47,20 +48,24 @@ public static void main(String[] args) throws IOException, SQLException { DatabaseConnector dc = new DatabaseConnector(); ConnectionInitializer ci = new ConnectionInitializer(); - ci.getManager().addEventListener(new AuditLogCommandListener(dc)); - ci.getManager().addEventListener(new AuditLogListener(dc)); - ci.getManager().addEventListener(new GuildVoiceListener(dc)); - ci.getManager().addEventListener(new GuildMemberJoinAndLeaveListener(dc)); - ci.getManager().addEventListener(new ServerBoostListener(dc)); - ci.getManager().addEventListener(new BotKickListener(dc)); - ci.getManager().addEventListener(new MessageLogCommandListener(dc)); - ci.getManager().addEventListener(new MessageLogListener(dc)); - - ci.getManager().addEventListener(new ServerStatListener()); - ci.getManager().addEventListener(new BotInfoListener()); - ci.getManager().addEventListener(new BotSetupListener()); - ci.getManager().addEventListener(new AnnouncementListener(dc)); - ci.getManager().addEventListener(new RequiredPermissionCheckListener()); + ShardManager manager = ci.getManager(); + + manager.addEventListener(new AuditLogSetupCommandListener(dc)); + manager.addEventListener(new AuditLogListener(dc)); + + manager.addEventListener(new MessageLogSetupCommandListener(dc)); + manager.addEventListener(new MessageLogListener(dc)); + + manager.addEventListener(new GuildVoiceListener(dc)); + manager.addEventListener(new GuildMemberJoinAndLeaveListener(dc)); + manager.addEventListener(new ServerBoostListener(dc)); + manager.addEventListener(new BotKickListener(dc)); + + manager.addEventListener(new ServerStatCommandListener()); + manager.addEventListener(new BotInfoCommandListener()); + manager.addEventListener(new BotSetupCommandListener()); + manager.addEventListener(new AnnouncementCommandListener(dc)); + manager.addEventListener(new RequiredPermissionCheckCommandListener()); /* * This is required only to set up a cron-job to periodically ping this end-point so that From 6a96688435e7a148cfd86d61b6bcb1c2a4a4400a Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Fri, 18 Jul 2025 14:55:41 +0530 Subject: [PATCH 11/16] Refactor listeners to use shared virtual thread pool All event listeners handling blocking I/O now accept an Executor for I/O operations, and FireRun provides a shared virtual thread pool to each listener. This improves concurrency and resource management by running blocking operations off the main thread. Minor TODO comments for logging were also added in data access classes. --- .../papertrail/cleanup/BotKickListener.java | 20 +-- .../papertrail/database/GuildDataAccess.java | 3 +- .../database/MessageDataAccess.java | 2 +- .../guildlisteners/ServerBoostListener.java | 94 ++++++------ .../loglisteners/AuditLogListener.java | 26 ++-- .../loglisteners/MessageLogListener.java | 9 +- .../GuildMemberJoinAndLeaveListener.java | 135 ++++++++++-------- .../voicelisteners/GuildVoiceListener.java | 102 ++++++------- .../java/org/papertrail/main/FireRun.java | 19 ++- 9 files changed, 222 insertions(+), 188 deletions(-) diff --git a/src/main/java/org/papertrail/cleanup/BotKickListener.java b/src/main/java/org/papertrail/cleanup/BotKickListener.java index 26ec55cd..ceba7f9e 100644 --- a/src/main/java/org/papertrail/cleanup/BotKickListener.java +++ b/src/main/java/org/papertrail/cleanup/BotKickListener.java @@ -3,32 +3,34 @@ import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; -import org.tinylog.Logger; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import java.util.concurrent.Executor; + /* * This class will have methods that unregister the log channels from the database after the bot has been kicked */ public class BotKickListener extends ListenerAdapter { - private DatabaseConnector dc; + private final Executor vThreadPool; + private final DatabaseConnector dc; - public BotKickListener(DatabaseConnector dc) { + public BotKickListener(DatabaseConnector dc, Executor vThreadPool) { this.dc = dc; + this.vThreadPool = vThreadPool; } @Override public void onGuildLeave(@NotNull GuildLeaveEvent event) { - try { - Guild leftGuild = event.getGuild(); + + Guild leftGuild = event.getGuild(); + vThreadPool.execute(()->{ dc.getGuildDataAccess().unregister(leftGuild.getId(), TableNames.AUDIT_LOG_TABLE); dc.getGuildDataAccess().unregister(leftGuild.getId(), TableNames.MESSAGE_LOG_REGISTRATION_TABLE); - } catch (Exception e) { - Logger.error(e, "Could not auto-unregister guild upon guild leave: " + event.getGuild().getId() + "/" - + event.getGuild().getName()); - } + }); + } } diff --git a/src/main/java/org/papertrail/database/GuildDataAccess.java b/src/main/java/org/papertrail/database/GuildDataAccess.java index 62faa32e..f5ac1b8a 100644 --- a/src/main/java/org/papertrail/database/GuildDataAccess.java +++ b/src/main/java/org/papertrail/database/GuildDataAccess.java @@ -8,8 +8,9 @@ import static org.jooq.impl.DSL.selectOne; import static org.jooq.impl.DSL.table; +// TODO Add logging public class GuildDataAccess { - + private final DSLContext dsl; private static final String GUILD_ID_COLUMN = "guild_id"; diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java index f39596ad..4f4001dc 100644 --- a/src/main/java/org/papertrail/database/MessageDataAccess.java +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -6,7 +6,7 @@ import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.selectOne; import static org.jooq.impl.DSL.table; - +// TODO Add Logging public class MessageDataAccess { private final DSLContext dsl; diff --git a/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java b/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java index 3bcc4064..8277be7b 100644 --- a/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java +++ b/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java @@ -3,7 +3,10 @@ import java.awt.Color; import java.time.Instant; import java.time.OffsetDateTime; +import java.util.Objects; +import java.util.concurrent.Executor; +import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; @@ -15,55 +18,58 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter; public class ServerBoostListener extends ListenerAdapter { - - private DatabaseConnector dc; - public ServerBoostListener(DatabaseConnector dc) { + private final Executor vThreadPool; + private final DatabaseConnector dc; + + public ServerBoostListener(DatabaseConnector dc, Executor vThreadPool) { this.dc=dc; + this.vThreadPool = vThreadPool; } @Override - public void onGuildMemberUpdateBoostTime(GuildMemberUpdateBoostTimeEvent event) { - - // this will return a non-null text id if a channel was previously registered in the database - // server boost logs are mapped to audit log table - String registeredChannelId=dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + public void onGuildMemberUpdateBoostTime(@NotNull GuildMemberUpdateBoostTimeEvent event) { - if(registeredChannelId==null ||registeredChannelId.isBlank()) { - return; - } - - Member member = event.getMember(); - Guild guild = event.getGuild(); - - String mentionableMember = (member!=null ? member.getAsMention() : "Unknown Member"); - - OffsetDateTime newBoostTime = event.getNewTimeBoosted(); // Will be null if the member stopped boosting - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸš€ Server Boost Event "); - eb.setThumbnail(guild.getIconUrl()); - - if (newBoostTime != null) { - eb.setDescription("πŸŽ‰ **" + guild.getName() + "** has been boosted!"); - eb.setColor(Color.PINK); - eb.addField("πŸ”‹ Booster Gained", "β•°β”ˆβž€"+mentionableMember+" has started boosting your server", false); - eb.addField("πŸ“ˆ Total Boosts In The Server", "β•°β”ˆβž€"+guild.getBoostCount(), false); - eb.addField("πŸŽ–οΈ Current Boost Tier", "β•°β”ˆβž€"+guild.getBoostTier().toString(), false); - } else { - eb.setDescription("⚠️ **" + guild.getName() + "** has lost a boost."); - eb.setColor(Color.GRAY); - eb.addField("πŸͺ« Booster Lost", "β•°β”ˆβž€"+mentionableMember+" has removed their boost from your server", false); - eb.addField("πŸ“‰ Remaining Boosts In The Server", "β•°β”ˆβž€"+guild.getBoostCount(), false); - eb.addField("πŸŽ–οΈ Current Boost Tier", "β•°β”ˆβž€"+guild.getBoostTier().toString(), false); - eb.addField("Notice", "Boosts remain active for a period even after a member stops boosting, so the server's boost count doesn't update immediately.", false); - } - - eb.setFooter("Server Boost Detection"); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); - } + vThreadPool.execute(()->{ + // this will return a non-null text id if a channel was previously registered in the database + // server boost logs are mapped to audit log table + String registeredChannelId=dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + + if(registeredChannelId==null ||registeredChannelId.isBlank()) { + return; + } + + Member member = event.getMember(); + Guild guild = event.getGuild(); + + String mentionableMember = member.getAsMention(); + OffsetDateTime newBoostTime = event.getNewTimeBoosted(); // Will be null if the member stopped boosting + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸš€ Server Boost Event "); + eb.setThumbnail(guild.getIconUrl()); + + if (newBoostTime != null) { + eb.setDescription("πŸŽ‰ **" + guild.getName() + "** has been boosted!"); + eb.setColor(Color.PINK); + eb.addField("πŸ”‹ Booster Gained", "β•°β”ˆβž€"+mentionableMember+" has started boosting your server", false); + eb.addField("πŸ“ˆ Total Boosts In The Server", "β•°β”ˆβž€"+guild.getBoostCount(), false); + eb.addField("πŸŽ–οΈ Current Boost Tier", "β•°β”ˆβž€"+ guild.getBoostTier(), false); + } else { + eb.setDescription("⚠️ **" + guild.getName() + "** has lost a boost."); + eb.setColor(Color.GRAY); + eb.addField("πŸͺ« Booster Lost", "β•°β”ˆβž€"+mentionableMember+" has removed their boost from your server", false); + eb.addField("πŸ“‰ Remaining Boosts In The Server", "β•°β”ˆβž€"+guild.getBoostCount(), false); + eb.addField("πŸŽ–οΈ Current Boost Tier", "β•°β”ˆβž€"+ guild.getBoostTier(), false); + eb.addField("Notice", "Boosts remain active for a period even after a member stops boosting, so the server's boost count doesn't update immediately.", false); + } + + eb.setFooter("Server Boost Detection"); + eb.setTimestamp(Instant.now()); + + MessageEmbed mb = eb.build(); + Objects.requireNonNull(event.getGuild().getTextChannelById(registeredChannelId)).sendMessageEmbeds(mb).queue(); + }); + } } diff --git a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java index 2d88f199..edf4a829 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java @@ -5,8 +5,10 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.concurrent.Executor; import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; import org.papertrail.utilities.ColorFormatter; @@ -35,24 +37,28 @@ public class AuditLogListener extends ListenerAdapter{ - private DatabaseConnector dc; + private final Executor vThreadPool; + private final DatabaseConnector dc; - public AuditLogListener(DatabaseConnector dc) { + public AuditLogListener(DatabaseConnector dc, Executor vThreadPool) { this.dc=dc; + this.vThreadPool = vThreadPool; } @Override - public void onGuildAuditLogEntryCreate(GuildAuditLogEntryCreateEvent event) { + public void onGuildAuditLogEntryCreate(@NotNull GuildAuditLogEntryCreateEvent event) { - // this will return a non-null text id if a channel was previously registered in the database - String registeredChannelId=dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + vThreadPool.execute(()->{ + // this will return a non-null text id if a channel was previously registered in the database + String registeredChannelId=dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); - if(registeredChannelId==null ||registeredChannelId.isBlank()) { - return; - } + if(registeredChannelId==null ||registeredChannelId.isBlank()) { + return; + } - AuditLogEntry ale = event.getEntry(); - auditLogParser(event, ale, registeredChannelId); + AuditLogEntry ale = event.getEntry(); + auditLogParser(event, ale, registeredChannelId); + }); } private void auditLogParser(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { diff --git a/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java index 4b0ba954..ef1a93a1 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java @@ -4,7 +4,6 @@ import java.time.Instant; import java.util.Objects; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; import org.papertrail.database.AuthorAndMessageEntity; import org.papertrail.database.DatabaseConnector; @@ -20,12 +19,12 @@ public class MessageLogListener extends ListenerAdapter { - private final Executor vThreadPool = Executors.newVirtualThreadPerTaskExecutor(); - private final DatabaseConnector dc; - public MessageLogListener(DatabaseConnector dc) { + private final Executor vThreadPool; + + public MessageLogListener(DatabaseConnector dc, Executor vThreadPool) { this.dc = dc; - + this.vThreadPool = vThreadPool; } @Override diff --git a/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java b/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java index 9f243992..27be2c82 100644 --- a/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java +++ b/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java @@ -2,7 +2,9 @@ import java.awt.Color; import java.time.Instant; +import java.util.concurrent.Executor; +import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; import org.papertrail.utilities.DurationFormatter; @@ -16,75 +18,82 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter; public class GuildMemberJoinAndLeaveListener extends ListenerAdapter { - - private DatabaseConnector dc; - public GuildMemberJoinAndLeaveListener (DatabaseConnector dc) { + private final Executor vThreadPool; + private final DatabaseConnector dc; + + public GuildMemberJoinAndLeaveListener (DatabaseConnector dc, Executor vThreadPool) { this.dc=dc; + this.vThreadPool = vThreadPool; } @Override - public void onGuildMemberJoin(GuildMemberJoinEvent event) { - - // this will return a non-null text id if a channel was previously registered in - // the database - // guild member join and leave events are mapped to audit log table - String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); - - if (registeredChannelId == null || registeredChannelId.isBlank()) { - return; - } - - Guild guild = event.getGuild(); - User user = event.getUser(); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ›¬ Member Join Event"); - eb.setDescription("A Member has joined "+guild.getName()); - eb.setColor(Color.GREEN); - - eb.addField("🏷️ Member Name", "β•°β”ˆβž€"+user.getName(), false); - eb.setThumbnail(user.getEffectiveAvatarUrl()); - eb.addField("ℹ️ Member Mention", "β•°β”ˆβž€"+user.getAsMention(), false); - eb.addField("πŸ†” Member ID", "β•°β”ˆβž€"+user.getId(), false); - eb.addField("πŸ“… Account Created", "β•°β”ˆβž€"+DurationFormatter.isoToLocalTimeCounter(user.getTimeCreated()), false); - eb.addField("πŸ€– Is Application ?", "β•°β”ˆβž€"+((Boolean.TRUE.equals(user.isBot())) ? "βœ…" : "❌"), false); - eb.setFooter("Member Join Detection"); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); + public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) { + + vThreadPool.execute(()->{ + // this will return a non-null text id if a channel was previously registered in + // the database + // guild member join and leave events are mapped to audit log table + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + + if (registeredChannelId == null || registeredChannelId.isBlank()) { + return; + } + + Guild guild = event.getGuild(); + User user = event.getUser(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ›¬ Member Join Event"); + eb.setDescription("A Member has joined "+guild.getName()); + eb.setColor(Color.GREEN); + + eb.addField("🏷️ Member Name", "β•°β”ˆβž€"+user.getName(), false); + eb.setThumbnail(user.getEffectiveAvatarUrl()); + eb.addField("ℹ️ Member Mention", "β•°β”ˆβž€"+user.getAsMention(), false); + eb.addField("πŸ†” Member ID", "β•°β”ˆβž€"+user.getId(), false); + eb.addField("πŸ“… Account Created", "β•°β”ˆβž€"+DurationFormatter.isoToLocalTimeCounter(user.getTimeCreated()), false); + eb.addField("πŸ€– Is Application ?", "β•°β”ˆβž€"+((user.isBot()) ? "βœ…" : "❌"), false); + eb.setFooter("Member Join Detection"); + eb.setTimestamp(Instant.now()); + + MessageEmbed mb = eb.build(); + + event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); + }); } - + @Override - public void onGuildMemberRemove(GuildMemberRemoveEvent event) { - - // this will return a non-null text id if a channel was previously registered in - // the database - String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); - - if (registeredChannelId == null || registeredChannelId.isBlank()) { - return; - } - - Guild guild = event.getGuild(); - User user = event.getUser(); - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ›« Member Leave Event"); - eb.setDescription("A Member has left "+guild.getName()); - eb.setColor(Color.RED); - - eb.addField("🏷️ Member Name", "β•°β”ˆβž€"+user.getName(), false); - eb.setThumbnail(user.getEffectiveAvatarUrl()); - eb.addField("πŸ†” Member ID", "β•°β”ˆβž€"+user.getId(), false); - - eb.setFooter("Member Leave Detection"); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); + public void onGuildMemberRemove(@NotNull GuildMemberRemoveEvent event) { + + vThreadPool.execute(() -> { + // this will return a non-null text id if a channel was previously registered in + // the database + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + + if (registeredChannelId == null || registeredChannelId.isBlank()) { + return; + } + + Guild guild = event.getGuild(); + User user = event.getUser(); + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ›« Member Leave Event"); + eb.setDescription("A Member has left "+guild.getName()); + eb.setColor(Color.RED); + + eb.addField("🏷️ Member Name", "β•°β”ˆβž€"+user.getName(), false); + eb.setThumbnail(user.getEffectiveAvatarUrl()); + eb.addField("πŸ†” Member ID", "β•°β”ˆβž€"+user.getId(), false); + + eb.setFooter("Member Leave Detection"); + eb.setTimestamp(Instant.now()); + + MessageEmbed mb = eb.build(); + + event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); + }); } + } diff --git a/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java b/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java index b63268f1..ef3d2582 100644 --- a/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java +++ b/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java @@ -2,7 +2,9 @@ import java.awt.Color; import java.time.Instant; +import java.util.concurrent.Executor; +import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; @@ -14,58 +16,62 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter; public class GuildVoiceListener extends ListenerAdapter { - - private DatabaseConnector dc; - public GuildVoiceListener(DatabaseConnector dc) { + private final Executor vThreadPool; + private final DatabaseConnector dc; + + public GuildVoiceListener(DatabaseConnector dc, Executor vThreadPool) { this.dc=dc; + this.vThreadPool = vThreadPool; } @Override - public void onGuildVoiceUpdate(GuildVoiceUpdateEvent event) { - - // this will return a non-null text id if a channel was previously registered in - // the database - // guild voice events are mapped to audit log table - String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); - - if (registeredChannelId == null || registeredChannelId.isBlank()) { - return; - } - - EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ”Š Voice Activity Log"); - - Member member = event.getMember(); - AudioChannel left = event.getOldValue(); // can be null if user joined for first time - AudioChannel joined = event.getNewValue(); // can be null if user left - - if(left==null && joined!=null) { - // User has joined a vc - eb.setDescription("A Member has joined a voice channel"); - eb.setColor(Color.GREEN); - eb.addField("βœ… Member Joined", "β•°β”ˆβž€"+member.getAsMention()+" joined the voice channel "+joined.getAsMention(), false); - } - - if (left != null && joined != null) { - // Moved from one channel to another - eb.setDescription("A Member has switched voice channels"); - eb.setColor(Color.YELLOW); - eb.addField("πŸ”„ Member Switched Channels", "β•°β”ˆβž€"+member.getAsMention()+" joined the switched from channel "+left.getAsMention()+ " to "+joined.getAsMention(), false); - } - - if (left!=null && joined==null) { - // User disconnected voluntarily (or was disconnected by a moderator) - eb.setDescription("A Member has left a voice channel"); - eb.setColor(Color.RED); - eb.addField("❌ Member Left A Voice Channel", "β•°β”ˆβž€"+member.getAsMention()+" left the voice channel "+left.getAsMention(), false); - } - - eb.setFooter("Voice Activity Detection"); - eb.setTimestamp(Instant.now()); - - MessageEmbed mb = eb.build(); - - event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); + public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) { + + vThreadPool.execute(()->{ + // this will return a non-null text id if a channel was previously registered in + // the database + // guild voice events are mapped to audit log table + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), TableNames.AUDIT_LOG_TABLE); + + if (registeredChannelId == null || registeredChannelId.isBlank()) { + return; + } + + EmbedBuilder eb = new EmbedBuilder(); + eb.setTitle("πŸ”Š Voice Activity Log"); + + Member member = event.getMember(); + AudioChannel left = event.getOldValue(); // can be null if user joined for first time + AudioChannel joined = event.getNewValue(); // can be null if user left + + if(left==null && joined!=null) { + // User has joined a vc + eb.setDescription("A Member has joined a voice channel"); + eb.setColor(Color.GREEN); + eb.addField("βœ… Member Joined", "β•°β”ˆβž€"+member.getAsMention()+" joined the voice channel "+joined.getAsMention(), false); + } + + if (left != null && joined != null) { + // Moved from one channel to another + eb.setDescription("A Member has switched voice channels"); + eb.setColor(Color.YELLOW); + eb.addField("πŸ”„ Member Switched Channels", "β•°β”ˆβž€"+member.getAsMention()+" joined the switched from channel "+left.getAsMention()+ " to "+joined.getAsMention(), false); + } + + if (left!=null && joined==null) { + // User disconnected voluntarily (or was disconnected by a moderator) + eb.setDescription("A Member has left a voice channel"); + eb.setColor(Color.RED); + eb.addField("❌ Member Left A Voice Channel", "β•°β”ˆβž€"+member.getAsMention()+" left the voice channel "+left.getAsMention(), false); + } + + eb.setFooter("Voice Activity Detection"); + eb.setTimestamp(Instant.now()); + + MessageEmbed mb = eb.build(); + + event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); + }); } } diff --git a/src/main/java/org/papertrail/main/FireRun.java b/src/main/java/org/papertrail/main/FireRun.java index 2f6d47d2..5def22d4 100644 --- a/src/main/java/org/papertrail/main/FireRun.java +++ b/src/main/java/org/papertrail/main/FireRun.java @@ -4,6 +4,8 @@ import java.net.InetSocketAddress; import java.security.Security; import java.sql.SQLException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import net.dv8tion.jda.api.sharding.ShardManager; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -30,7 +32,10 @@ * The main class of the bot */ public class FireRun { - + + // All I/O blocking operations run inside the vThreadPool + private static final Executor vThreadPool = Executors.newVirtualThreadPerTaskExecutor(); + // Register Bouncy Castle as a security provider // Required for the PBEWITHSHA256AND256BITAES-CBC-BC encryption algorithm private static void registerBouncyCastle() { @@ -51,15 +56,15 @@ public static void main(String[] args) throws IOException, SQLException { ShardManager manager = ci.getManager(); manager.addEventListener(new AuditLogSetupCommandListener(dc)); - manager.addEventListener(new AuditLogListener(dc)); + manager.addEventListener(new AuditLogListener(dc, vThreadPool)); manager.addEventListener(new MessageLogSetupCommandListener(dc)); - manager.addEventListener(new MessageLogListener(dc)); + manager.addEventListener(new MessageLogListener(dc, vThreadPool)); - manager.addEventListener(new GuildVoiceListener(dc)); - manager.addEventListener(new GuildMemberJoinAndLeaveListener(dc)); - manager.addEventListener(new ServerBoostListener(dc)); - manager.addEventListener(new BotKickListener(dc)); + manager.addEventListener(new GuildVoiceListener(dc, vThreadPool)); + manager.addEventListener(new GuildMemberJoinAndLeaveListener(dc, vThreadPool)); + manager.addEventListener(new ServerBoostListener(dc, vThreadPool)); + manager.addEventListener(new BotKickListener(dc, vThreadPool)); manager.addEventListener(new ServerStatCommandListener()); manager.addEventListener(new BotInfoCommandListener()); From e0ef5ee835c749dacb345edac1466bb86c050d9a Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Fri, 18 Jul 2025 18:14:12 +0530 Subject: [PATCH 12/16] Add per-message locking to MessageLogListener Introduces Guava's Striped locks and an AtomicLong to ensure thread-safe operations on messages in MessageLogListener. Database operations for logging, updating, and deleting messages are now wrapped in a lock per message ID to prevent race conditions. Guava dependency added to pom.xml. --- pom.xml | 7 ++++- .../loglisteners/MessageLogListener.java | 29 +++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index c8df87e9..b6667fe1 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,12 @@ org.bouncycastle bcprov-jdk18on 1.81 - + + + com.google.guava + guava + 33.4.8-jre + diff --git a/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java index ef1a93a1..2e2114f4 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java @@ -4,7 +4,10 @@ import java.time.Instant; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Lock; +import com.google.common.util.concurrent.Striped; import org.papertrail.database.AuthorAndMessageEntity; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; @@ -16,16 +19,31 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.tinylog.Logger; public class MessageLogListener extends ListenerAdapter { private final DatabaseConnector dc; private final Executor vThreadPool; + private final Striped messageLocks = Striped.lock(8192); + private final AtomicLong activeLockCount = new AtomicLong(0); public MessageLogListener(DatabaseConnector dc, Executor vThreadPool) { this.dc = dc; this.vThreadPool = vThreadPool; } + + private void withMessageLock (String messageId, Runnable task) { + Lock lock = messageLocks.get(messageId); + lock.lock(); + Logger.info("Lock acquired for message id: {} . Active lock count: {}", messageId, activeLockCount.incrementAndGet()); + try{ + task.run(); + } finally { + lock.unlock(); + Logger.info("Lock released for message id: {} . Active lock count: {}", messageId, activeLockCount.decrementAndGet()); + } + } @Override public void onMessageReceived(MessageReceivedEvent event) { @@ -49,9 +67,10 @@ public void onMessageReceived(MessageReceivedEvent event) { } // else if the registered guild id matches with the event fetched guild id, log the message with its ID and author - vThreadPool.execute(()-> - dc.getMessageDataAccess().logMessage(event.getMessageId(), event.getMessage().getContentRaw(), event.getAuthor().getId()) - ); + vThreadPool.execute(()-> { + String messageId = event.getMessageId(); + withMessageLock(messageId, ()-> dc.getMessageDataAccess().logMessage(messageId, event.getMessage().getContentRaw(), event.getAuthor().getId())); + }); } @@ -97,7 +116,7 @@ public void onMessageUpdate(MessageUpdateEvent event) { eb.setFooter(event.getGuild().getName()); eb.setTimestamp(Instant.now()); // update the database with the new message - dc.getMessageDataAccess().updateMessage(messageId, updatedMessage); + withMessageLock(messageId, ()->dc.getMessageDataAccess().updateMessage(messageId, updatedMessage)); // the reason this is above the send queue is because in case where the user did not give sufficient permissions to // the bot, the error responses wouldn't block the update of the message in the database. @@ -146,7 +165,7 @@ public void onMessageDelete(MessageDeleteEvent event) { eb.setTimestamp(Instant.now()); // delete the message from the database - dc.getMessageDataAccess().deleteMessage(messageId); + withMessageLock(messageId, ()->dc.getMessageDataAccess().deleteMessage(messageId)); // the reason this is above the send queue is because in case where the user did not give sufficient permissions to // the bot, (such as no send message permissions) the exceptions wouldn't block the deletion in the database. From f37088601a309b7090d862b0a0d688f33e82fe43 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Sun, 20 Jul 2025 09:32:08 +0530 Subject: [PATCH 13/16] Make key fields final and fix bitmask map keys Marked key fields as final in several listener classes to ensure immutability. Simplified the bitmask map keys in GuildSystemChannelFlagResolver and PermissionResolver by replacing '1L << 0' with '1L'. --- .../commandlisteners/AuditLogSetupCommandListener.java | 2 +- .../commandlisteners/MessageLogSetupCommandListener.java | 2 +- src/main/java/org/papertrail/main/ActivityUpdateListener.java | 2 +- .../papertrail/utilities/GuildSystemChannelFlagResolver.java | 2 +- src/main/java/org/papertrail/utilities/PermissionResolver.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java index 972ea2eb..725c2e6d 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java @@ -16,7 +16,7 @@ public class AuditLogSetupCommandListener extends ListenerAdapter { - private DatabaseConnector dc; + private final DatabaseConnector dc; public AuditLogSetupCommandListener(DatabaseConnector dc) { diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java index 8cd73f43..f46e3047 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java @@ -17,7 +17,7 @@ public class MessageLogSetupCommandListener extends ListenerAdapter { - private DatabaseConnector dc; + private final DatabaseConnector dc; private final EmbedBuilder eb = new EmbedBuilder(); public MessageLogSetupCommandListener(DatabaseConnector dc) { diff --git a/src/main/java/org/papertrail/main/ActivityUpdateListener.java b/src/main/java/org/papertrail/main/ActivityUpdateListener.java index 74054915..f69b6d47 100644 --- a/src/main/java/org/papertrail/main/ActivityUpdateListener.java +++ b/src/main/java/org/papertrail/main/ActivityUpdateListener.java @@ -14,7 +14,7 @@ */ public class ActivityUpdateListener extends ListenerAdapter { - private ShardManager manager; + private final ShardManager manager; public ActivityUpdateListener(ShardManager manager) { this.manager = manager; diff --git a/src/main/java/org/papertrail/utilities/GuildSystemChannelFlagResolver.java b/src/main/java/org/papertrail/utilities/GuildSystemChannelFlagResolver.java index 46150e56..f79862fd 100644 --- a/src/main/java/org/papertrail/utilities/GuildSystemChannelFlagResolver.java +++ b/src/main/java/org/papertrail/utilities/GuildSystemChannelFlagResolver.java @@ -5,7 +5,7 @@ public class GuildSystemChannelFlagResolver { private static final Map SYSTEM_CHANNEL_FLAG_MAP = Map.ofEntries( - Map.entry(1L << 0, "Suppress member join notifications"), + Map.entry(1L, "Suppress member join notifications"), Map.entry(1L << 1, "Suppress server boost notifications"), Map.entry(1L << 2, "Suppress server setup tips"), Map.entry(1L << 3, "Hide member join sticker reply buttons"), diff --git a/src/main/java/org/papertrail/utilities/PermissionResolver.java b/src/main/java/org/papertrail/utilities/PermissionResolver.java index 457e1635..0481a989 100644 --- a/src/main/java/org/papertrail/utilities/PermissionResolver.java +++ b/src/main/java/org/papertrail/utilities/PermissionResolver.java @@ -5,7 +5,7 @@ public class PermissionResolver { private static final Map PERMISSION_MAP = Map.ofEntries( - Map.entry(1L << 0, "CREATE_INSTANT_INVITE"), + Map.entry(1L, "CREATE_INSTANT_INVITE"), Map.entry(1L << 1, "KICK_MEMBERS"), Map.entry(1L << 2, "BAN_MEMBERS"), Map.entry(1L << 3, "ADMINISTRATOR"), From a58bf3ace0e8a032667946b44a4455674a291dcd Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Sun, 20 Jul 2025 10:05:20 +0530 Subject: [PATCH 14/16] Add null safety and refactor for modern Java features Replaces custom POJO with Java record for AuthorAndMessageEntity, adds Objects.requireNonNull assertions throughout listeners for improved null safety, and updates integer parsing to use primitive int in TypeResolver. Also removes unnecessary SQLException handling in main and database connector constructors, and applies minor code cleanups and assertion checks for better reliability and readability. --- .../database/AuthorAndMessageEntity.java | 20 +-- .../database/DatabaseConnector.java | 4 +- .../AnnouncementCommandListener.java | 9 +- .../AuditLogSetupCommandListener.java | 7 +- .../MessageLogSetupCommandListener.java | 7 +- ...equiredPermissionCheckCommandListener.java | 16 +- .../ServerStatCommandListener.java | 18 ++- .../loglisteners/AuditLogListener.java | 143 +++++++++--------- .../loglisteners/MessageLogListener.java | 12 +- .../GuildMemberJoinAndLeaveListener.java | 5 +- .../voicelisteners/GuildVoiceListener.java | 3 +- .../java/org/papertrail/main/FireRun.java | 3 +- .../papertrail/utilities/TypeResolver.java | 8 +- 13 files changed, 122 insertions(+), 133 deletions(-) diff --git a/src/main/java/org/papertrail/database/AuthorAndMessageEntity.java b/src/main/java/org/papertrail/database/AuthorAndMessageEntity.java index 736c1085..98fe2dae 100644 --- a/src/main/java/org/papertrail/database/AuthorAndMessageEntity.java +++ b/src/main/java/org/papertrail/database/AuthorAndMessageEntity.java @@ -1,22 +1,6 @@ package org.papertrail.database; -public class AuthorAndMessageEntity { - - private final String authorId; - private final String messageContent; - - public AuthorAndMessageEntity(String authorId, String messageContent) { - super(); - this.authorId = authorId; - this.messageContent = messageContent; - } - - public String getAuthorId() { - return authorId; - } +public record AuthorAndMessageEntity(String authorId, String messageContent) { + - public String getMessageContent() { - return messageContent; - } - } diff --git a/src/main/java/org/papertrail/database/DatabaseConnector.java b/src/main/java/org/papertrail/database/DatabaseConnector.java index 577021ed..f8bb6468 100644 --- a/src/main/java/org/papertrail/database/DatabaseConnector.java +++ b/src/main/java/org/papertrail/database/DatabaseConnector.java @@ -1,7 +1,5 @@ package org.papertrail.database; -import java.sql.SQLException; - import org.jooq.DSLContext; import org.jooq.SQLDialect; import org.jooq.impl.DSL; @@ -16,7 +14,7 @@ public class DatabaseConnector { private static HikariDataSource dataSource; private final DSLContext dsl; - public DatabaseConnector() throws SQLException { + public DatabaseConnector() { initializeDataSource(); this.dsl = DSL.using(dataSource, SQLDialect.POSTGRES); } diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java index 6b1e6694..9ea6ca2f 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java @@ -3,6 +3,7 @@ import java.awt.Color; import java.time.Instant; import java.util.List; +import java.util.Objects; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; @@ -42,12 +43,12 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { } EmbedBuilder eb = new EmbedBuilder(); - eb.setTitle("πŸ“£ " +ProjectInfo.APPNAME+" Announcement: "+event.getOption("type").getAsString()); - eb.setDescription("πŸ“ " +event.getOption("description").getAsString()); + eb.setTitle("πŸ“£ " +ProjectInfo.APPNAME+" Announcement: "+ Objects.requireNonNull(event.getOption("type")).getAsString()); + eb.setDescription("πŸ“ " + Objects.requireNonNull(event.getOption("description")).getAsString()); eb.setThumbnail(AuthorInfo.AUTHOR_AVATAR_URL); eb.setColor(Color.WHITE); - eb.addField("🏷️ Detail", "β•°β”ˆβž€"+event.getOption("detail").getAsString(), false); + eb.addField("🏷️ Detail", "β•°β”ˆβž€"+ Objects.requireNonNull(event.getOption("detail")).getAsString(), false); OptionMapping extra = event.getOption("extra"); if(extra!=null) { eb.addField("🏷️ Extras", "β•°β”ˆβž€"+extra.getAsString(), false); @@ -62,7 +63,7 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { for(String registeredChannel: registeredChannelList) { TextChannel channelToSendTo = event.getJDA().getTextChannelById(registeredChannel); if(channelToSendTo!=null) { - event.getJDA().getTextChannelById(registeredChannel).sendMessageEmbeds(mb).queue(); // TODO implement rate-limitation beyond JDA's system + Objects.requireNonNull(event.getJDA().getTextChannelById(registeredChannel)).sendMessageEmbeds(mb).queue(); // TODO implement rate-limitation beyond JDA's system } } } diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java index 725c2e6d..0330a924 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java @@ -1,6 +1,7 @@ package org.papertrail.listeners.commandlisteners; import java.awt.Color; +import java.util.Objects; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; @@ -55,7 +56,7 @@ private void setAuditLogging(SlashCommandInteractionEvent event) { return; } - String guildId = event.getGuild().getId(); + String guildId = Objects.requireNonNull(event.getGuild()).getId(); // retrieve the previously registered channel_id associated with the given // guild_id String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.AUDIT_LOG_TABLE); @@ -114,7 +115,7 @@ private void retrieveAuditLoggingChannel(SlashCommandInteractionEvent event) { return; } - String guildId = event.getGuild().getId(); + String guildId = Objects.requireNonNull(event.getGuild()).getId(); // retrieve the channel_id registered in the database String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.AUDIT_LOG_TABLE); @@ -164,7 +165,7 @@ private void unsetAuditLogging(SlashCommandInteractionEvent event) { return; } - String guildId = event.getGuild().getId(); + String guildId = Objects.requireNonNull(event.getGuild()).getId(); String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.AUDIT_LOG_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java index f46e3047..77b420e3 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java @@ -1,6 +1,7 @@ package org.papertrail.listeners.commandlisteners; import java.awt.Color; +import java.util.Objects; import org.papertrail.database.DatabaseConnector; import org.papertrail.database.TableNames; @@ -58,7 +59,7 @@ private void setMessageLogging(SlashCommandInteractionEvent event) { } Guild guild = event.getGuild(); - String guildId = guild.getId(); + String guildId = Objects.requireNonNull(guild).getId(); String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); @@ -113,7 +114,7 @@ private void retrieveMessageLoggingChannel(SlashCommandInteractionEvent event) { } Guild guild = event.getGuild(); - String guildId = guild.getId(); + String guildId = Objects.requireNonNull(guild).getId(); String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); // if there is no channel_id for the given guild_id in the database, then inform @@ -154,7 +155,7 @@ private void unsetMessageLogging(SlashCommandInteractionEvent event) { } Guild guild = event.getGuild(); - String guildId = guild.getId(); + String guildId = Objects.requireNonNull(guild).getId(); String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java index a7a81a0c..a0c641f4 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java @@ -25,15 +25,17 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { Guild guild = event.getGuild(); SelfUser botAsUser = event.getJDA().getSelfUser(); - Role botIntegrationRole = guild.getRoleByBot(botAsUser); + assert guild != null; + Role botIntegrationRole = guild.getRoleByBot(botAsUser); Member botMember = guild.getMember(botAsUser); EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("PaperTrail Permissions Checker"); eb.setDescription("Helps determine whether the required permissions are granted for PaperTrail to function properly"); eb.setColor(Color.MAGENTA); - - eb.addField("Bot Integration Role Specific Permission", (botIntegrationRole.hasPermission(Permission.VIEW_AUDIT_LOGS) ? "βœ…" : "❌")+Permission.VIEW_AUDIT_LOGS.getName(), false); + + assert botIntegrationRole != null; + eb.addField("Bot Integration Role Specific Permission", (botIntegrationRole.hasPermission(Permission.VIEW_AUDIT_LOGS) ? "βœ…" : "❌")+Permission.VIEW_AUDIT_LOGS.getName(), false); // create a map of required permissions and set all their statuses to false Map requiredPermissions = new EnumMap<>(Permission.class); @@ -57,10 +59,10 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { }); StringBuilder finalPermissions = new StringBuilder(); - requiredPermissions.entrySet().forEach(permission -> { - finalPermissions.append(Boolean.TRUE.equals(permission.getValue()) ? "βœ…" : "❌"); - finalPermissions.append(permission.getKey().getName()+System.lineSeparator()); - }); + requiredPermissions.forEach((key, value) -> { + finalPermissions.append(Boolean.TRUE.equals(value) ? "βœ…" : "❌"); + finalPermissions.append(key.getName()).append(System.lineSeparator()); + }); eb.addField("Channel Specific Permissions: "+currentChannel.getAsMention(), finalPermissions.toString(), false); diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/ServerStatCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/ServerStatCommandListener.java index 5fb7c6fb..cde7ea0c 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/ServerStatCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/ServerStatCommandListener.java @@ -3,6 +3,7 @@ import java.awt.Color; import java.time.Instant; import java.util.List; +import java.util.Objects; import org.papertrail.utilities.DurationFormatter; @@ -22,11 +23,12 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { if(event.getName().equals("stats")) { Guild guild = event.getGuild(); - - List members = guild.getMemberCache().asList(); - Integer botCount = 0; - Integer userCount = 0; - Integer onlineUserCount = 0; + + assert guild != null; + List members = Objects.requireNonNull(guild).getMemberCache().asList(); + int botCount = 0; + int userCount = 0; + int onlineUserCount = 0; for(Member member: members) { if(member.getUser().isBot()) { botCount++; @@ -48,7 +50,7 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { eb.setColor(Color.PINK); eb.addField("🏠 Guild Name", "β•°β”ˆβž€"+guild.getName(), false); - eb.addField("πŸ‘‘ Guild Owner", "β•°β”ˆβž€"+guild.getMemberById(guild.getOwnerId()).getAsMention(), false); + eb.addField("πŸ‘‘ Guild Owner", "β•°β”ˆβž€"+ Objects.requireNonNull(guild.getMemberById(guild.getOwnerId())).getAsMention(), false); eb.addField("πŸ“… Guild Created On", "β•°β”ˆβž€"+DurationFormatter.isoToLocalTimeCounter(guild.getTimeCreated()), false); eb.addField("πŸ”— Guild Vanity URL", "β•°β”ˆβž€"+(guild.getVanityUrl() !=null ? guild.getVanityUrl() : "Not Set"), false); @@ -64,7 +66,7 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { eb.addField("πŸš€ Guild Boosters ", "β•°β”ˆβž€"+mentionableBoosters, false); eb.addField("πŸ’– Guild Boost Count", "β•°β”ˆβž€"+guild.getBoostCount(), false); eb.addField("πŸ“Ž Booster Role", "β•°β”ˆβž€"+(guild.getBoostRole() !=null ? guild.getBoostRole().getAsMention() : "No Boost Role Found"), false); - eb.addField("πŸ—Ό Boost Tier", "β•°β”ˆβž€"+guild.getBoostTier().toString(), false); + eb.addField("πŸ—Ό Boost Tier", "β•°β”ˆβž€"+ guild.getBoostTier(), false); eb.addField("🌐 Locale", "β•°β”ˆβž€"+guild.getLocale().getNativeName(), true); eb.addField("πŸ”’ Verification", "β•°β”ˆβž€"+guild.getVerificationLevel().name(), true); @@ -73,7 +75,7 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { eb.addField("πŸ’¬ Text Channels", "β•°β”ˆβž€"+guild.getTextChannels().size(), true); eb.addField("πŸ”Š Voice Channels", "β•°β”ˆβž€"+guild.getVoiceChannels().size(), true); - eb.addField("πŸ“‹ Data Requested By", "β•°β”ˆβž€"+event.getMember().getAsMention(), false); + eb.addField("πŸ“‹ Data Requested By", "β•°β”ˆβž€"+ Objects.requireNonNull(event.getMember()).getAsMention(), false); eb.setFooter("πŸ“‹ Stats By: PaperTrail πŸ“‹"); eb.setTimestamp(Instant.now()); diff --git a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java index edf4a829..a97813fe 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java @@ -1,10 +1,9 @@ package org.papertrail.listeners.loglisteners; import java.awt.Color; -import java.util.Arrays; -import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.concurrent.Executor; import org.apache.commons.lang3.StringUtils; @@ -171,7 +170,7 @@ private void formatGeneric(GuildAuditLogEntryCreateEvent event, AuditLogEntry al eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatInviteCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale , String channelIdToSendTo) { @@ -232,7 +231,7 @@ private void formatInviteCreate(GuildAuditLogEntryCreateEvent event, AuditLogEnt MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } @@ -289,7 +288,7 @@ private void formatInviteDelete(GuildAuditLogEntryCreateEvent event, AuditLogEnt MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatKick(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -317,10 +316,10 @@ private void formatKick(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, eb.addField("πŸ“ With Reason", "β•°β”ˆβž€"+(reason!=null ? reason : "No Reason Provided"), false); eb.setFooter("Audit Log Entry ID: "+ale.getId()); - eb.setTimestamp(ale.getTimeCreated()); + eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); - }); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); + }); }); } @@ -350,7 +349,7 @@ private void formatBan(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, S eb.setFooter("Audit Log Entry ID: "+ale.getId()); eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); }); }); } @@ -379,7 +378,7 @@ private void formatUnban(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, eb.setFooter("Audit Log Entry ID: "+ale.getId()); eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); }); }); } @@ -396,7 +395,7 @@ private void formatMemberUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEnt String mentionableTarget = (target !=null ? target.getAsMention() : ale.getTargetId()); eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following member was updated"); - eb.setThumbnail(event.getGuild().getMemberById(ale.getTargetId()).getEffectiveAvatarUrl()); + eb.setThumbnail(Objects.requireNonNull(event.getGuild().getMemberById(ale.getTargetId())).getEffectiveAvatarUrl()); eb.setColor(Color.CYAN); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); @@ -425,9 +424,9 @@ private void formatMemberUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEnt case "nick": if(oldValue!=null && newValue==null) { // resetting to default nickname eb.addField("🏷️ Nickname Update", "β•°β”ˆβž€"+"Reset "+mentionableTarget+"'s name", false); - } else if(oldValue!=null && newValue!=null) { // changing from one nickname to another + } else if(oldValue != null) { // changing from one nickname to another eb.addField("🏷️ Nickname Update", "β•°β”ˆβž€"+"Updated "+mentionableTarget+"'s name from "+oldValue+ " to "+ newValue, false); - } else if(oldValue==null && newValue!=null) { // changing from default nickname to a new nickname + } else if(newValue != null) { // changing from default nickname to a new nickname eb.addField("🏷️ Nickname Update", "β•°β”ˆβž€"+"Set "+mentionableTarget+"'s name as "+ newValue, false); } break; @@ -454,7 +453,7 @@ private void formatMemberUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEnt MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatBotAdd(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -480,7 +479,7 @@ private void formatBotAdd(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatIntegrationCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -522,7 +521,7 @@ private void formatIntegrationCreate(GuildAuditLogEntryCreateEvent event, AuditL MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatIntegrationDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -564,7 +563,7 @@ private void formatIntegrationDelete(GuildAuditLogEntryCreateEvent event, AuditL MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatChannelCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -631,7 +630,7 @@ private void formatChannelCreate(GuildAuditLogEntryCreateEvent event, AuditLogEn MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatChannelUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -725,7 +724,7 @@ private void formatChannelUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEn MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatChannelDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -775,7 +774,7 @@ private void formatChannelDelete(GuildAuditLogEntryCreateEvent event, AuditLogEn MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatChannelOverrideCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -848,7 +847,7 @@ private void formatChannelOverrideCreate(GuildAuditLogEntryCreateEvent event, Au MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatChannelOverrideUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -875,13 +874,13 @@ private void formatChannelOverrideUpdate(GuildAuditLogEntryCreateEvent event, Au String mentionableOverrideTarget = overriddenId; if ("0".equals(overriddenType)) { // It’s a role - Role role = event.getGuild().getRoleById(overriddenId); + Role role = event.getGuild().getRoleById(Objects.requireNonNull(overriddenId)); if (role != null) { mentionableOverrideTarget = role.getAsMention(); } } else if ("1".equals(overriddenType)) { // It’s a member - Member member = event.getGuild().getMemberById(overriddenId); + Member member = event.getGuild().getMemberById(Objects.requireNonNull(overriddenId)); if (member != null) { mentionableOverrideTarget = member.getAsMention(); } @@ -923,7 +922,7 @@ private void formatChannelOverrideUpdate(GuildAuditLogEntryCreateEvent event, Au MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatChannelOverrideDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -963,7 +962,7 @@ private void formatChannelOverrideDelete(GuildAuditLogEntryCreateEvent event, Au break; case "allow": - /// the newValue will return null if an over-ride is deleted but we're not concerned with newValue + // the newValue will return null if an over-ride is deleted but we're not concerned with newValue // the oldValue returns the permissions the channel was previously allowed eb.addField("Previously Allowed Permissions", PermissionResolver.getParsedPermissions(oldValue, "βœ…"), false); break; @@ -995,7 +994,7 @@ private void formatChannelOverrideDelete(GuildAuditLogEntryCreateEvent event, Au MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatAutoModRuleCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1023,13 +1022,13 @@ private void formatAutoModRuleCreate(GuildAuditLogEntryCreateEvent event, AuditL case "exempt_roles": String roleIds = String.valueOf(newValue); String cleanedRoleIds = StringUtils.strip(roleIds, "[]"); - List roleIdList = Arrays.asList(StringUtils.split(cleanedRoleIds, ",")); + String[] roleIdList = StringUtils.split(cleanedRoleIds, ","); StringBuilder mentionableRoles = new StringBuilder(); for(String roleId : roleIdList) { Role r = ale.getGuild().getRoleById(roleId.strip()); mentionableRoles.append(r!=null ? r.getAsMention() : roleId.strip()).append(", "); } - eb.addField("βœ”οΈ Exempt Roles: ", "β•°β”ˆβž€"+mentionableRoles.toString(), false); + eb.addField("βœ”οΈ Exempt Roles: ", "β•°β”ˆβž€"+ mentionableRoles, false); break; case "enabled": @@ -1047,13 +1046,13 @@ private void formatAutoModRuleCreate(GuildAuditLogEntryCreateEvent event, AuditL case "exempt_channels": String channelIds = String.valueOf(newValue); String cleanedChannelIds = StringUtils.strip(channelIds, "[]"); - List channelIdList = Arrays.asList(StringUtils.split(cleanedChannelIds, ",")); + String[] channelIdList = StringUtils.split(cleanedChannelIds, ","); StringBuilder mentionableChannels = new StringBuilder(); for(String channelId : channelIdList) { GuildChannel r = ale.getGuild().getGuildChannelById(channelId.strip()); mentionableChannels.append(r!=null ? r.getAsMention() : channelId.strip()).append(", "); } - eb.addField("βœ”οΈ Exempt Channels: ", "β•°β”ˆβž€"+mentionableChannels.toString(), false); + eb.addField("βœ”οΈ Exempt Channels: ", "β•°β”ˆβž€"+ mentionableChannels, false); break; case "event_type": @@ -1078,7 +1077,7 @@ private void formatAutoModRuleCreate(GuildAuditLogEntryCreateEvent event, AuditL MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatAutoModRuleDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1120,7 +1119,7 @@ private void formatAutoModRuleDelete(GuildAuditLogEntryCreateEvent event, AuditL MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatAutoModRuleUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1148,13 +1147,13 @@ private void formatAutoModRuleUpdate(GuildAuditLogEntryCreateEvent event, AuditL case "exempt_roles": String roleIds = String.valueOf(newValue); String cleanedRoleIds = StringUtils.strip(roleIds, "[]"); - List roleIdList = Arrays.asList(StringUtils.split(cleanedRoleIds, ",")); + String[] roleIdList = StringUtils.split(cleanedRoleIds, ","); StringBuilder mentionableRoles = new StringBuilder(); for(String roleId : roleIdList) { Role r = ale.getGuild().getRoleById(roleId.strip()); mentionableRoles.append(r!=null ? r.getAsMention() : roleId.strip()).append(", "); } - eb.addField("βœ”οΈ New Exempt Roles: ", "β•°β”ˆβž€"+mentionableRoles.toString(), false); + eb.addField("βœ”οΈ New Exempt Roles: ", "β•°β”ˆβž€"+ mentionableRoles, false); break; @@ -1165,13 +1164,13 @@ private void formatAutoModRuleUpdate(GuildAuditLogEntryCreateEvent event, AuditL case "exempt_channels": String channelIds = String.valueOf(newValue); String cleanedChannelIds = StringUtils.strip(channelIds, "[]"); - List channelIdList = Arrays.asList(StringUtils.split(cleanedChannelIds, ",")); + String[] channelIdList = StringUtils.split(cleanedChannelIds, ","); StringBuilder mentionableChannels = new StringBuilder(); for(String channelId : channelIdList) { GuildChannel r = ale.getGuild().getGuildChannelById(channelId.strip()); mentionableChannels.append(r!=null ? r.getAsMention() : channelId.strip()).append(", "); } - eb.addField("βœ”οΈ New Exempt Channels: ", "β•°β”ˆβž€"+mentionableChannels.toString(), false); + eb.addField("βœ”οΈ New Exempt Channels: ", "β•°β”ˆβž€"+ mentionableChannels, false); break; @@ -1193,7 +1192,7 @@ private void formatAutoModRuleUpdate(GuildAuditLogEntryCreateEvent event, AuditL MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatEmojiCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1233,7 +1232,7 @@ private void formatEmojiCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntr MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatEmojiUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1272,7 +1271,7 @@ private void formatEmojiUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntr MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatEmojiDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1311,7 +1310,7 @@ private void formatEmojiDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntr MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatStickerCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1366,7 +1365,7 @@ private void formatStickerCreate(GuildAuditLogEntryCreateEvent event, AuditLogEn MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatStickerDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1419,7 +1418,7 @@ private void formatStickerDelete(GuildAuditLogEntryCreateEvent event, AuditLogEn MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatStickerUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1437,7 +1436,7 @@ private void formatStickerUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEn eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); - eb.addField("🏷️ Target Sticker Name", targetSticker.getName(), false); + eb.addField("🏷️ Target Sticker Name", Objects.requireNonNull(targetSticker).getName(), false); eb.addField("πŸ”— Target Sticker Url", targetSticker.getIconUrl(), false); for(Entry changes: ale.getChanges().entrySet()) { @@ -1473,7 +1472,7 @@ private void formatStickerUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEn MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatGuildUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1580,7 +1579,7 @@ private void formatGuildUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntr MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatMemberRoleUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1594,7 +1593,7 @@ private void formatMemberRoleUpdate(GuildAuditLogEntryCreateEvent event, AuditLo String mentionableTarget = (target !=null ? target.getAsMention() : ale.getTargetId()); eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following member role was updated"); - eb.setThumbnail(event.getGuild().getMemberById(ale.getTargetIdLong()).getEffectiveAvatarUrl()); + eb.setThumbnail(Objects.requireNonNull(event.getGuild().getMemberById(ale.getTargetIdLong())).getEffectiveAvatarUrl()); eb.setColor(Color.CYAN); eb.addField("Action Type", String.valueOf(ale.getType()), true); @@ -1634,7 +1633,7 @@ private void formatMemberRoleUpdate(GuildAuditLogEntryCreateEvent event, AuditLo MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatRoleCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1684,7 +1683,7 @@ private void formatRoleCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatRoleUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1758,7 +1757,7 @@ private void formatRoleUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatRoleDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1819,7 +1818,7 @@ private void formatRoleDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } // the audit log does not expose much information regarding member vc move and kick events @@ -1841,7 +1840,7 @@ private void formatMemberVoiceKick(GuildAuditLogEntryCreateEvent event, AuditLog eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatMemberVoiceMove(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1861,7 +1860,7 @@ private void formatMemberVoiceMove(GuildAuditLogEntryCreateEvent event, AuditLog eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatVoiceChannelStatusUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1884,7 +1883,7 @@ private void formatVoiceChannelStatusUpdate(GuildAuditLogEntryCreateEvent event, eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatVoiceChannelStatusDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1907,7 +1906,7 @@ private void formatVoiceChannelStatusDelete(GuildAuditLogEntryCreateEvent event, eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatAutoModFlagToChannel(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1927,7 +1926,7 @@ private void formatAutoModFlagToChannel(GuildAuditLogEntryCreateEvent event, Aud eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatAutoModMemberTimeout (GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1947,7 +1946,7 @@ private void formatAutoModMemberTimeout (GuildAuditLogEntryCreateEvent event, Au eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatAutoModRuleBlockMessage (GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1967,7 +1966,7 @@ private void formatAutoModRuleBlockMessage (GuildAuditLogEntryCreateEvent event, eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatMessagePin(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -1987,7 +1986,7 @@ private void formatMessagePin(GuildAuditLogEntryCreateEvent event, AuditLogEntry eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } // these audit log events don't expose anything other than the executor of the event private void formatMessageUnpin(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2007,7 +2006,7 @@ private void formatMessageUnpin(GuildAuditLogEntryCreateEvent event, AuditLogEnt eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatStageInstanceCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2048,7 +2047,7 @@ private void formatStageInstanceCreate(GuildAuditLogEntryCreateEvent event, Audi eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatStageInstanceUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2091,7 +2090,7 @@ private void formatStageInstanceUpdate(GuildAuditLogEntryCreateEvent event, Audi eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatStageInstanceDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2132,7 +2131,7 @@ private void formatStageInstanceDelete(GuildAuditLogEntryCreateEvent event, Audi eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatScheduledEventCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2192,7 +2191,7 @@ private void formatScheduledEventCreate(GuildAuditLogEntryCreateEvent event, Aud eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatScheduledEventUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2204,7 +2203,7 @@ private void formatScheduledEventUpdate(GuildAuditLogEntryCreateEvent event, Aud String mentionableExecutor = (executor != null ? executor.getAsMention() : ale.getUserId()); ScheduledEvent targetEvent = event.getGuild().getScheduledEventById(ale.getTargetId()); - eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following scheduled event was updated: "+targetEvent.getName()); + eb.setDescription("πŸ‘€ **By**: "+mentionableExecutor+"\nℹ️ The following scheduled event was updated: "+ Objects.requireNonNull(targetEvent).getName()); eb.setColor(Color.YELLOW); eb.addField("Action Type", String.valueOf(ale.getType()), true); eb.addField("Target Type", String.valueOf(ale.getTargetType()), true); @@ -2260,7 +2259,7 @@ private void formatScheduledEventUpdate(GuildAuditLogEntryCreateEvent event, Aud eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatScheduledEventDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2320,7 +2319,7 @@ private void formatScheduledEventDelete(GuildAuditLogEntryCreateEvent event, Aud eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatThreadCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2383,7 +2382,7 @@ private void formatThreadCreate(GuildAuditLogEntryCreateEvent event, AuditLogEnt eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatThreadUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2461,7 +2460,7 @@ private void formatThreadUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEnt eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatThreadDelete(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2520,7 +2519,7 @@ private void formatThreadDelete(GuildAuditLogEntryCreateEvent event, AuditLogEnt eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatWebhookCreate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2571,7 +2570,7 @@ private void formatWebhookCreate(GuildAuditLogEntryCreateEvent event, AuditLogEn eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatWebhookUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2622,7 +2621,7 @@ private void formatWebhookUpdate(GuildAuditLogEntryCreateEvent event, AuditLogEn eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } private void formatWebhookRemove(GuildAuditLogEntryCreateEvent event, AuditLogEntry ale, String channelIdToSendTo) { @@ -2673,6 +2672,6 @@ private void formatWebhookRemove(GuildAuditLogEntryCreateEvent event, AuditLogEn eb.setTimestamp(ale.getTimeCreated()); MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(channelIdToSendTo).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); } } diff --git a/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java index 2e2114f4..500abb2b 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java @@ -93,7 +93,7 @@ public void onMessageUpdate(MessageUpdateEvent event) { // fetch the old message content and its author from the database AuthorAndMessageEntity ame = dc.getMessageDataAccess().retrieveAuthorAndMessage(messageId); - if(ame==null || ame.getAuthorId()==null || ame.getAuthorId().isBlank()) { // would be true only if the unedited message was not logged in the first place + if(ame==null || ame.authorId()==null || ame.authorId().isBlank()) { // would be true only if the unedited message was not logged in the first place return; } // fetch the updated message and its author from the event @@ -101,7 +101,7 @@ public void onMessageUpdate(MessageUpdateEvent event) { // Ignore events where the message content wasn't edited (e.g., pin, embed resolve, thread creates and updates) // This is required since MessageUpdateEvent is triggered in case of pins and embed resolves with no change to content - if(updatedMessage.equals(ame.getMessageContent())) { + if(updatedMessage.equals(ame.messageContent())) { return; } @@ -110,7 +110,7 @@ public void onMessageUpdate(MessageUpdateEvent event) { eb.setDescription("A message sent by "+event.getAuthor().getAsMention()+" has been edited in: "+event.getJumpUrl()); eb.setColor(Color.YELLOW); - eb.addField("Old Message", ame.getMessageContent(), false); // get only the message and not the author + eb.addField("Old Message", ame.messageContent(), false); // get only the message and not the author eb.addField("New Message", updatedMessage, false); eb.setFooter(event.getGuild().getName()); @@ -152,14 +152,14 @@ public void onMessageDelete(MessageDeleteEvent event) { // retrieve the stored message in the database which was deleted AuthorAndMessageEntity ame = dc.getMessageDataAccess().retrieveAuthorAndMessage(messageId); - User author = event.getJDA().getUserById(ame.getAuthorId()); - String mentionableAuthor = (author !=null ? author.getAsMention() : ame.getAuthorId()); + User author = event.getJDA().getUserById(ame.authorId()); + String mentionableAuthor = (author !=null ? author.getAsMention() : ame.authorId()); EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("πŸ—‘οΈ Message Delete Event"); eb.setDescription("A message sent by "+mentionableAuthor+" has been deleted"); eb.setColor(Color.RED); - eb.addField("Deleted Message", ame.getMessageContent(), false); + eb.addField("Deleted Message", ame.messageContent(), false); eb.setFooter(event.getGuild().getName()); eb.setTimestamp(Instant.now()); diff --git a/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java b/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java index 27be2c82..47bd0f6d 100644 --- a/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java +++ b/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java @@ -2,6 +2,7 @@ import java.awt.Color; import java.time.Instant; +import java.util.Objects; import java.util.concurrent.Executor; import org.jetbrains.annotations.NotNull; @@ -59,7 +60,7 @@ public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) { MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(registeredChannelId)).sendMessageEmbeds(mb).queue(); }); } @@ -92,7 +93,7 @@ public void onGuildMemberRemove(@NotNull GuildMemberRemoveEvent event) { MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(registeredChannelId)).sendMessageEmbeds(mb).queue(); }); } diff --git a/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java b/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java index ef3d2582..61a7c7a0 100644 --- a/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java +++ b/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java @@ -2,6 +2,7 @@ import java.awt.Color; import java.time.Instant; +import java.util.Objects; import java.util.concurrent.Executor; import org.jetbrains.annotations.NotNull; @@ -71,7 +72,7 @@ public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) { MessageEmbed mb = eb.build(); - event.getGuild().getTextChannelById(registeredChannelId).sendMessageEmbeds(mb).queue(); + Objects.requireNonNull(event.getGuild().getTextChannelById(registeredChannelId)).sendMessageEmbeds(mb).queue(); }); } } diff --git a/src/main/java/org/papertrail/main/FireRun.java b/src/main/java/org/papertrail/main/FireRun.java index 5def22d4..28f155df 100644 --- a/src/main/java/org/papertrail/main/FireRun.java +++ b/src/main/java/org/papertrail/main/FireRun.java @@ -3,7 +3,6 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.security.Security; -import java.sql.SQLException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -46,7 +45,7 @@ private static void registerBouncyCastle() { } } - public static void main(String[] args) throws IOException, SQLException { + public static void main(String[] args) throws IOException { registerBouncyCastle(); diff --git a/src/main/java/org/papertrail/utilities/TypeResolver.java b/src/main/java/org/papertrail/utilities/TypeResolver.java index 0c0f56a1..5a086e02 100644 --- a/src/main/java/org/papertrail/utilities/TypeResolver.java +++ b/src/main/java/org/papertrail/utilities/TypeResolver.java @@ -157,7 +157,7 @@ public static String guildVerificationLevelResolver(Object type) { } try { - Integer t = Integer.parseInt(type.toString()); + int t = Integer.parseInt(type.toString()); return switch (t) { case 0 -> "NONE"; case 1 -> "LOW (Verified Email)"; @@ -178,7 +178,7 @@ public static String explicitFilterTypeResolver(Object type) { } try { - Integer t = Integer.parseInt(type.toString()); + int t = Integer.parseInt(type.toString()); return switch (t) { case 0 -> "No Filter"; case 1 -> "Filter Messages From Server Members Without Roles"; @@ -197,7 +197,7 @@ public static String scheduleEventTypeResolver(Object type) { } try { - Integer t = Integer.parseInt(type.toString()); + int t = Integer.parseInt(type.toString()); return switch (t) { case 1 -> "Stage Event"; case 2 -> "Voice Event"; @@ -216,7 +216,7 @@ public static String scheduleEventStatusTypeResolver(Object type) { } try { - Integer t = Integer.parseInt(type.toString()); + int t = Integer.parseInt(type.toString()); return switch (t) { case 1 -> "Scheduled"; case 2 -> "Active"; From 2d085b5263ada287267cb5d3e48175c674081f3b Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Sun, 20 Jul 2025 10:13:08 +0530 Subject: [PATCH 15/16] Show multiple required permissions for bot role Updated the embed field to display both VIEW_AUDIT_LOGS and MANAGE_SERVER permissions for the bot integration role, providing clearer visibility of required permissions. --- .../RequiredPermissionCheckCommandListener.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java index a0c641f4..95b88a56 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/RequiredPermissionCheckCommandListener.java @@ -35,7 +35,13 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { eb.setColor(Color.MAGENTA); assert botIntegrationRole != null; - eb.addField("Bot Integration Role Specific Permission", (botIntegrationRole.hasPermission(Permission.VIEW_AUDIT_LOGS) ? "βœ…" : "❌")+Permission.VIEW_AUDIT_LOGS.getName(), false); + String botRoleRequiredPermissions = (botIntegrationRole.hasPermission(Permission.VIEW_AUDIT_LOGS) ? "βœ…" : "❌") + + Permission.VIEW_AUDIT_LOGS.getName() + + System.lineSeparator() + + (botIntegrationRole.hasPermission(Permission.MANAGE_SERVER) ? "βœ…" : "❌") + + Permission.MANAGE_SERVER.getName(); + + eb.addField("Bot Integration Role Specific Permission", botRoleRequiredPermissions, false); // create a map of required permissions and set all their statuses to false Map requiredPermissions = new EnumMap<>(Permission.class); From 79074a0c2e14e67d4aee727284b270a14d8c1eb4 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Sun, 20 Jul 2025 10:41:23 +0530 Subject: [PATCH 16/16] Remove obsolete TODO comments for logging Deleted TODO comments about adding logging in GuildDataAccess and MessageDataAccess classes. No functional changes were made. --- src/main/java/org/papertrail/database/GuildDataAccess.java | 1 - src/main/java/org/papertrail/database/MessageDataAccess.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/papertrail/database/GuildDataAccess.java b/src/main/java/org/papertrail/database/GuildDataAccess.java index f5ac1b8a..bd5dbdfe 100644 --- a/src/main/java/org/papertrail/database/GuildDataAccess.java +++ b/src/main/java/org/papertrail/database/GuildDataAccess.java @@ -8,7 +8,6 @@ import static org.jooq.impl.DSL.selectOne; import static org.jooq.impl.DSL.table; -// TODO Add logging public class GuildDataAccess { private final DSLContext dsl; diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java index 4f4001dc..f39596ad 100644 --- a/src/main/java/org/papertrail/database/MessageDataAccess.java +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -6,7 +6,7 @@ import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.selectOne; import static org.jooq.impl.DSL.table; -// TODO Add Logging + public class MessageDataAccess { private final DSLContext dsl;