From aadf88451de6e0fee9f88c3646748f9c2f76f495 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 31 Jul 2025 14:30:24 +0530 Subject: [PATCH 1/5] Refactor table and column names to Schema class Replaces the TableNames utility with a new Schema class that centralizes all table and column name constants and provides schema initialization logic. Updates all references throughout the codebase to use Schema instead of TableNames, and removes redundant column name definitions from data access classes. This change improves maintainability and ensures consistent usage of database schema identifiers. --- .../papertrail/cleanup/BotKickListener.java | 6 +- .../database/DatabaseConnector.java | 4 + .../papertrail/database/GuildDataAccess.java | 7 +- .../database/MessageDataAccess.java | 17 ++--- .../java/org/papertrail/database/Schema.java | 73 +++++++++++++++++++ .../org/papertrail/database/TableNames.java | 12 --- .../AnnouncementCommandListener.java | 4 +- .../AuditLogSetupCommandListener.java | 12 +-- .../MessageLogSetupCommandListener.java | 12 +-- .../guildlisteners/ServerBoostListener.java | 4 +- .../loglisteners/AuditLogListener.java | 4 +- .../loglisteners/MessageLogListener.java | 12 +-- .../GuildMemberJoinAndLeaveListener.java | 6 +- .../voicelisteners/GuildVoiceListener.java | 4 +- 14 files changed, 120 insertions(+), 57 deletions(-) create mode 100644 src/main/java/org/papertrail/database/Schema.java delete mode 100644 src/main/java/org/papertrail/database/TableNames.java diff --git a/src/main/java/org/papertrail/cleanup/BotKickListener.java b/src/main/java/org/papertrail/cleanup/BotKickListener.java index ceba7f9e..63ec7303 100644 --- a/src/main/java/org/papertrail/cleanup/BotKickListener.java +++ b/src/main/java/org/papertrail/cleanup/BotKickListener.java @@ -2,7 +2,7 @@ import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; -import org.papertrail.database.TableNames; +import org.papertrail.database.Schema; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; @@ -28,8 +28,8 @@ public void onGuildLeave(@NotNull GuildLeaveEvent event) { 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); + dc.getGuildDataAccess().unregister(leftGuild.getId(), Schema.AUDIT_LOG_TABLE); + dc.getGuildDataAccess().unregister(leftGuild.getId(), Schema.MESSAGE_LOG_REGISTRATION_TABLE); }); } diff --git a/src/main/java/org/papertrail/database/DatabaseConnector.java b/src/main/java/org/papertrail/database/DatabaseConnector.java index f8bb6468..737e20fa 100644 --- a/src/main/java/org/papertrail/database/DatabaseConnector.java +++ b/src/main/java/org/papertrail/database/DatabaseConnector.java @@ -8,6 +8,9 @@ import com.zaxxer.hikari.HikariDataSource; +import static org.papertrail.database.Schema.initializeSchema; + + public class DatabaseConnector { private static final String DB_URL = EnvConfig.get("DATABASEURL"); @@ -17,6 +20,7 @@ public class DatabaseConnector { public DatabaseConnector() { initializeDataSource(); this.dsl = DSL.using(dataSource, SQLDialect.POSTGRES); + initializeSchema(dsl); } public GuildDataAccess getGuildDataAccess() { diff --git a/src/main/java/org/papertrail/database/GuildDataAccess.java b/src/main/java/org/papertrail/database/GuildDataAccess.java index bd5dbdfe..63aa8b90 100644 --- a/src/main/java/org/papertrail/database/GuildDataAccess.java +++ b/src/main/java/org/papertrail/database/GuildDataAccess.java @@ -7,14 +7,13 @@ import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.selectOne; import static org.jooq.impl.DSL.table; +import static org.papertrail.database.Schema.CHANNEL_ID_COLUMN; +import static org.papertrail.database.Schema.GUILD_ID_COLUMN; 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; } diff --git a/src/main/java/org/papertrail/database/MessageDataAccess.java b/src/main/java/org/papertrail/database/MessageDataAccess.java index f39596ad..359a6510 100644 --- a/src/main/java/org/papertrail/database/MessageDataAccess.java +++ b/src/main/java/org/papertrail/database/MessageDataAccess.java @@ -6,22 +6,21 @@ import static org.jooq.impl.DSL.field; import static org.jooq.impl.DSL.selectOne; import static org.jooq.impl.DSL.table; +import static org.papertrail.database.Schema.AUTHOR_ID_COLUMN; +import static org.papertrail.database.Schema.MESSAGE_CONTENT_COLUMN; +import static org.papertrail.database.Schema.MESSAGE_ID_COLUMN; 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)) + dsl.insertInto(table(Schema.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() @@ -31,7 +30,7 @@ public void logMessage(String messageId, String messageContent, String authorId) public AuthorAndMessageEntity retrieveAuthorAndMessage (String messageId) { return dsl.select(field(AUTHOR_ID_COLUMN), field(MESSAGE_CONTENT_COLUMN)) - .from(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) + .from(table(Schema.MESSAGE_LOG_CONTENT_TABLE)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) .fetchOne(r -> new AuthorAndMessageEntity(String.valueOf(r.get(field(AUTHOR_ID_COLUMN))), MessageEncryption.decrypt(String.valueOf(r.get(field(MESSAGE_CONTENT_COLUMN)))))); } @@ -39,14 +38,14 @@ public AuthorAndMessageEntity retrieveAuthorAndMessage (String messageId) { public boolean messageExists (String messageId) { return dsl.fetchExists( - selectOne().from(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) + selectOne().from(table(Schema.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)) + dsl.update(table(Schema.MESSAGE_LOG_CONTENT_TABLE)) .set(field(MESSAGE_CONTENT_COLUMN), MessageEncryption.encrypt(messageContent)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) .execute(); @@ -54,7 +53,7 @@ public void updateMessage (String messageId, String messageContent) { public void deleteMessage (String messageId) { - dsl.deleteFrom(table(TableNames.MESSAGE_LOG_CONTENT_TABLE)) + dsl.deleteFrom(table(Schema.MESSAGE_LOG_CONTENT_TABLE)) .where(field(MESSAGE_ID_COLUMN).eq(Long.parseLong(messageId))) .execute(); } diff --git a/src/main/java/org/papertrail/database/Schema.java b/src/main/java/org/papertrail/database/Schema.java new file mode 100644 index 00000000..fd2d0950 --- /dev/null +++ b/src/main/java/org/papertrail/database/Schema.java @@ -0,0 +1,73 @@ +package org.papertrail.database; + +import org.jooq.DSLContext; + +public class Schema { + + private Schema() { + throw new IllegalStateException("Utility Class"); + } + + public static final String SCHEMA_NAME = "public"; + + public static final String AUDIT_LOG_TABLE = "audit_log_table"; + public static final String MESSAGE_LOG_REGISTRATION_TABLE = "message_log_registration_table"; + // the following to column names are used in both tables: message_log_registration_table and audit_log_table + public static final String GUILD_ID_COLUMN = "guild_id"; + public static final String CHANNEL_ID_COLUMN = "channel_id"; + + public static final String MESSAGE_LOG_CONTENT_TABLE = "message_log_content_table"; + public static final String MESSAGE_ID_COLUMN = "message_id"; + public static final String MESSAGE_CONTENT_COLUMN = "message_content"; + public static final String AUTHOR_ID_COLUMN = "author_id"; + + public static void initializeSchema(DSLContext dsl) { + + String createSchema = String.format(""" + CREATE SCHEMA IF NOT EXISTS %s; + """, SCHEMA_NAME); + + dsl.execute(createSchema); + + String createAuditLogTable = String.format(""" + CREATE TABLE IF NOT EXISTS %s.%s ( + %s int8 NOT NULL, + %s int8 NOT NULL, + CONSTRAINT %s_pk PRIMARY KEY (%s), + CONSTRAINT %s_unique UNIQUE (%s) + ); + """, SCHEMA_NAME, AUDIT_LOG_TABLE, GUILD_ID_COLUMN, CHANNEL_ID_COLUMN, + AUDIT_LOG_TABLE, GUILD_ID_COLUMN, + AUDIT_LOG_TABLE, CHANNEL_ID_COLUMN); + + dsl.execute(createAuditLogTable); + + String createMessageLogRegistrationTable = String.format(""" + CREATE TABLE IF NOT EXISTS %s.%s ( + %s int8 NOT NULL, + %s int8 NOT NULL, + CONSTRAINT %s_pk PRIMARY KEY (%s), + CONSTRAINT %s_unique UNIQUE (%s) + ); + """, SCHEMA_NAME, MESSAGE_LOG_REGISTRATION_TABLE, GUILD_ID_COLUMN, CHANNEL_ID_COLUMN, + MESSAGE_LOG_REGISTRATION_TABLE, GUILD_ID_COLUMN, + MESSAGE_LOG_REGISTRATION_TABLE, CHANNEL_ID_COLUMN); + + dsl.execute(createMessageLogRegistrationTable); + + String createMessageLogContentTable = String.format(""" + CREATE TABLE IF NOT EXISTS %s.%s ( + %s int8 NOT NULL, + %s text NULL, + %s int8 NOT NULL, + created_at timestamp DEFAULT (CURRENT_TIMESTAMP AT TIME ZONE 'UTC'::text) NOT NULL, + CONSTRAINT %s_pk PRIMARY KEY (%s) + ); + CREATE INDEX IF NOT EXISTS %s_created_at_idx ON %s.%s USING btree (created_at); + """, SCHEMA_NAME, MESSAGE_LOG_CONTENT_TABLE, MESSAGE_ID_COLUMN, MESSAGE_CONTENT_COLUMN, AUTHOR_ID_COLUMN, + MESSAGE_LOG_CONTENT_TABLE, MESSAGE_ID_COLUMN, + MESSAGE_LOG_CONTENT_TABLE, SCHEMA_NAME, MESSAGE_LOG_CONTENT_TABLE); + + dsl.execute(createMessageLogContentTable); + } +} diff --git a/src/main/java/org/papertrail/database/TableNames.java b/src/main/java/org/papertrail/database/TableNames.java deleted file mode 100644 index 6bc3e047..00000000 --- a/src/main/java/org/papertrail/database/TableNames.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.papertrail.database; - -public class TableNames { - - private TableNames() { - throw new IllegalStateException("Utility Class"); - } - - public static final String AUDIT_LOG_TABLE = "audit_log_table"; - public static final String MESSAGE_LOG_REGISTRATION_TABLE = "message_log_registration_table"; - public static final String MESSAGE_LOG_CONTENT_TABLE = "message_log_content_table"; -} diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java index 9ea6ca2f..acd0d0dd 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/AnnouncementCommandListener.java @@ -6,7 +6,7 @@ import java.util.Objects; import org.papertrail.database.DatabaseConnector; -import org.papertrail.database.TableNames; +import org.papertrail.database.Schema; import org.papertrail.utilities.EnvConfig; import org.papertrail.version.AuthorInfo; import org.papertrail.version.ProjectInfo; @@ -36,7 +36,7 @@ public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { if(event.getName().equals("announcement")) { - List registeredChannelList = dc.getGuildDataAccess().retrieveAllRegisteredChannels(TableNames.AUDIT_LOG_TABLE); + List registeredChannelList = dc.getGuildDataAccess().retrieveAllRegisteredChannels(Schema.AUDIT_LOG_TABLE); if(registeredChannelList.isEmpty()) { return; diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java index 0330a924..7c978403 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/AuditLogSetupCommandListener.java @@ -4,7 +4,7 @@ import java.util.Objects; import org.papertrail.database.DatabaseConnector; -import org.papertrail.database.TableNames; +import org.papertrail.database.Schema; import org.tinylog.Logger; import net.dv8tion.jda.api.EmbedBuilder; @@ -59,7 +59,7 @@ private void setAuditLogging(SlashCommandInteractionEvent event) { 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); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, Schema.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 +83,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.getGuildDataAccess().registerGuildAndChannel(guildId, channelIdToRegister, TableNames.AUDIT_LOG_TABLE); + dc.getGuildDataAccess().registerGuildAndChannel(guildId, channelIdToRegister, Schema.AUDIT_LOG_TABLE); EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("📝 Audit Log Configuration"); @@ -118,7 +118,7 @@ private void retrieveAuditLoggingChannel(SlashCommandInteractionEvent event) { 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); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, Schema.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 +166,7 @@ private void unsetAuditLogging(SlashCommandInteractionEvent event) { } String guildId = Objects.requireNonNull(event.getGuild()).getId(); - String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.AUDIT_LOG_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, Schema.AUDIT_LOG_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { @@ -180,7 +180,7 @@ private void unsetAuditLogging(SlashCommandInteractionEvent event) { } else { try { - dc.getGuildDataAccess().unregister(guildId, TableNames.AUDIT_LOG_TABLE); + dc.getGuildDataAccess().unregister(guildId, Schema.AUDIT_LOG_TABLE); EmbedBuilder eb = new EmbedBuilder(); eb.setTitle("📝 Audit Log Configuration"); diff --git a/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java b/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java index 77b420e3..66f9961d 100644 --- a/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java +++ b/src/main/java/org/papertrail/listeners/commandlisteners/MessageLogSetupCommandListener.java @@ -4,7 +4,7 @@ import java.util.Objects; import org.papertrail.database.DatabaseConnector; -import org.papertrail.database.TableNames; +import org.papertrail.database.Schema; import org.tinylog.Logger; import net.dv8tion.jda.api.EmbedBuilder; @@ -61,7 +61,7 @@ private void setMessageLogging(SlashCommandInteractionEvent event) { Guild guild = event.getGuild(); String guildId = Objects.requireNonNull(guild).getId(); - String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, Schema.MESSAGE_LOG_REGISTRATION_TABLE); if(registeredChannelId!=null && !registeredChannelId.isBlank()) { @@ -79,7 +79,7 @@ private void setMessageLogging(SlashCommandInteractionEvent event) { String channelIdToRegister = event.getChannelId(); try { // register the channel_id along with guild_id in the database - dc.getGuildDataAccess().registerGuildAndChannel(guildId, channelIdToRegister, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + dc.getGuildDataAccess().registerGuildAndChannel(guildId, channelIdToRegister, Schema.MESSAGE_LOG_REGISTRATION_TABLE); eb.addField("✅ Channel Registration Success","╰┈➤"+"All edited and deleted messages will be logged here", false); eb.setColor(Color.GREEN); @@ -116,7 +116,7 @@ private void retrieveMessageLoggingChannel(SlashCommandInteractionEvent event) { Guild guild = event.getGuild(); String guildId = Objects.requireNonNull(guild).getId(); - String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, Schema.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 +157,7 @@ private void unsetMessageLogging(SlashCommandInteractionEvent event) { Guild guild = event.getGuild(); String guildId = Objects.requireNonNull(guild).getId(); - String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, Schema.MESSAGE_LOG_REGISTRATION_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { eb.addField("â„šī¸ Channel Removal", "╰┈➤"+"No channel has been registered for message logs", false); @@ -171,7 +171,7 @@ private void unsetMessageLogging(SlashCommandInteractionEvent event) { } else { try { - dc.getGuildDataAccess().unregister(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + dc.getGuildDataAccess().unregister(guildId, Schema.MESSAGE_LOG_REGISTRATION_TABLE); eb.addField("✅ Channel Removal", "╰┈➤"+"Channel successfully unset", false); eb.setColor(Color.GREEN); diff --git a/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java b/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java index 8277be7b..9aec2002 100644 --- a/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java +++ b/src/main/java/org/papertrail/listeners/guildlisteners/ServerBoostListener.java @@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; -import org.papertrail.database.TableNames; +import org.papertrail.database.Schema; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Guild; @@ -33,7 +33,7 @@ public void onGuildMemberUpdateBoostTime(@NotNull GuildMemberUpdateBoostTimeEven 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); + String registeredChannelId=dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), Schema.AUDIT_LOG_TABLE); if(registeredChannelId==null ||registeredChannelId.isBlank()) { return; diff --git a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java index a97813fe..e7e0869c 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/AuditLogListener.java @@ -9,7 +9,7 @@ import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; -import org.papertrail.database.TableNames; +import org.papertrail.database.Schema; import org.papertrail.utilities.ColorFormatter; import org.papertrail.utilities.DurationFormatter; import org.papertrail.utilities.GuildSystemChannelFlagResolver; @@ -49,7 +49,7 @@ public void onGuildAuditLogEntryCreate(@NotNull GuildAuditLogEntryCreateEvent ev 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); + String registeredChannelId=dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), Schema.AUDIT_LOG_TABLE); if(registeredChannelId==null ||registeredChannelId.isBlank()) { return; diff --git a/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java index 500abb2b..bec09c23 100644 --- a/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java +++ b/src/main/java/org/papertrail/listeners/loglisteners/MessageLogListener.java @@ -10,7 +10,7 @@ import com.google.common.util.concurrent.Striped; import org.papertrail.database.AuthorAndMessageEntity; import org.papertrail.database.DatabaseConnector; -import org.papertrail.database.TableNames; +import org.papertrail.database.Schema; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; @@ -62,7 +62,7 @@ public void onMessageReceived(MessageReceivedEvent event) { // 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)) { + if(!dc.getGuildDataAccess().isGuildRegistered(guildId, Schema.MESSAGE_LOG_REGISTRATION_TABLE)) { return; } @@ -83,7 +83,7 @@ public void onMessageUpdate(MessageUpdateEvent event) { } String guildId = event.getGuild().getId(); - if(!dc.getGuildDataAccess().isGuildRegistered(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE)) { + if(!dc.getGuildDataAccess().isGuildRegistered(guildId, Schema.MESSAGE_LOG_REGISTRATION_TABLE)) { return; } @@ -124,7 +124,7 @@ public void onMessageUpdate(MessageUpdateEvent event) { // 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); + String channelIdToSendTo = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, Schema.MESSAGE_LOG_REGISTRATION_TABLE); Objects.requireNonNull(event.getGuild().getTextChannelById(channelIdToSendTo)).sendMessageEmbeds(mb).queue(); }); } @@ -134,7 +134,7 @@ public void onMessageDelete(MessageDeleteEvent event) { String guildId = event.getGuild().getId(); - if(!dc.getGuildDataAccess().isGuildRegistered(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE)) { + if(!dc.getGuildDataAccess().isGuildRegistered(guildId, Schema.MESSAGE_LOG_REGISTRATION_TABLE)) { return; } @@ -148,7 +148,7 @@ public void onMessageDelete(MessageDeleteEvent event) { } // retrieve the channel id where the logs must be sent - String channelIdToSendTo = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, TableNames.MESSAGE_LOG_REGISTRATION_TABLE); + String channelIdToSendTo = dc.getGuildDataAccess().retrieveRegisteredChannel(guildId, Schema.MESSAGE_LOG_REGISTRATION_TABLE); // retrieve the stored message in the database which was deleted AuthorAndMessageEntity ame = dc.getMessageDataAccess().retrieveAuthorAndMessage(messageId); diff --git a/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java b/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java index 47bd0f6d..ef42928f 100644 --- a/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java +++ b/src/main/java/org/papertrail/listeners/memberlisteners/GuildMemberJoinAndLeaveListener.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; -import org.papertrail.database.TableNames; +import org.papertrail.database.Schema; import org.papertrail.utilities.DurationFormatter; import net.dv8tion.jda.api.EmbedBuilder; @@ -35,7 +35,7 @@ public void onGuildMemberJoin(@NotNull 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); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), Schema.AUDIT_LOG_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { return; @@ -70,7 +70,7 @@ 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); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), Schema.AUDIT_LOG_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { return; diff --git a/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java b/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java index 61a7c7a0..91aca914 100644 --- a/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java +++ b/src/main/java/org/papertrail/listeners/voicelisteners/GuildVoiceListener.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull; import org.papertrail.database.DatabaseConnector; -import org.papertrail.database.TableNames; +import org.papertrail.database.Schema; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.Member; @@ -33,7 +33,7 @@ public void onGuildVoiceUpdate(@NotNull 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); + String registeredChannelId = dc.getGuildDataAccess().retrieveRegisteredChannel(event.getGuild().getId(), Schema.AUDIT_LOG_TABLE); if (registeredChannelId == null || registeredChannelId.isBlank()) { return; From ad2d24003bac560083bbd6658b03e3c49cde7a71 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 31 Jul 2025 16:30:23 +0530 Subject: [PATCH 2/5] Refactor schema initialization to use jOOQ DSL Replaces raw SQL string execution with jOOQ's fluent API for schema and table creation in Schema.java, improving type safety and readability. Also sets the database connection time zone to UTC in DatabaseConnector. --- .../database/DatabaseConnector.java | 3 +- .../java/org/papertrail/database/Schema.java | 78 +++++++++---------- 2 files changed, 38 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/papertrail/database/DatabaseConnector.java b/src/main/java/org/papertrail/database/DatabaseConnector.java index 737e20fa..dec72b23 100644 --- a/src/main/java/org/papertrail/database/DatabaseConnector.java +++ b/src/main/java/org/papertrail/database/DatabaseConnector.java @@ -41,7 +41,8 @@ private static synchronized void initializeDataSource() { dataSource.setConnectionTimeout(30000); // 30 seconds dataSource.setIdleTimeout(600000); // 10 minutes dataSource.setMaxLifetime(1800000); // 30 minutes - dataSource.setPoolName("PaperTrailPool"); + dataSource.setPoolName("PaperTrailPool"); + dataSource.setConnectionInitSql("SET TIME ZONE 'UTC'"); } // Ensure the data source is closed on shutdown Runtime.getRuntime().addShutdownHook(new Thread(() -> { diff --git a/src/main/java/org/papertrail/database/Schema.java b/src/main/java/org/papertrail/database/Schema.java index fd2d0950..6f4b2be4 100644 --- a/src/main/java/org/papertrail/database/Schema.java +++ b/src/main/java/org/papertrail/database/Schema.java @@ -1,6 +1,10 @@ package org.papertrail.database; import org.jooq.DSLContext; +import org.jooq.impl.DSL; +import org.jooq.impl.SQLDataType; + +import static org.jooq.impl.DSL.constraint; public class Schema { @@ -23,51 +27,41 @@ private Schema() { public static void initializeSchema(DSLContext dsl) { - String createSchema = String.format(""" - CREATE SCHEMA IF NOT EXISTS %s; - """, SCHEMA_NAME); - - dsl.execute(createSchema); - - String createAuditLogTable = String.format(""" - CREATE TABLE IF NOT EXISTS %s.%s ( - %s int8 NOT NULL, - %s int8 NOT NULL, - CONSTRAINT %s_pk PRIMARY KEY (%s), - CONSTRAINT %s_unique UNIQUE (%s) - ); - """, SCHEMA_NAME, AUDIT_LOG_TABLE, GUILD_ID_COLUMN, CHANNEL_ID_COLUMN, - AUDIT_LOG_TABLE, GUILD_ID_COLUMN, - AUDIT_LOG_TABLE, CHANNEL_ID_COLUMN); - - dsl.execute(createAuditLogTable); + dsl.createSchemaIfNotExists(SCHEMA_NAME).execute(); - String createMessageLogRegistrationTable = String.format(""" - CREATE TABLE IF NOT EXISTS %s.%s ( - %s int8 NOT NULL, - %s int8 NOT NULL, - CONSTRAINT %s_pk PRIMARY KEY (%s), - CONSTRAINT %s_unique UNIQUE (%s) - ); - """, SCHEMA_NAME, MESSAGE_LOG_REGISTRATION_TABLE, GUILD_ID_COLUMN, CHANNEL_ID_COLUMN, - MESSAGE_LOG_REGISTRATION_TABLE, GUILD_ID_COLUMN, - MESSAGE_LOG_REGISTRATION_TABLE, CHANNEL_ID_COLUMN); + // create audit log table + dsl.createTableIfNotExists(AUDIT_LOG_TABLE) + .column(GUILD_ID_COLUMN, SQLDataType.BIGINT.notNull()) + .column(CHANNEL_ID_COLUMN, SQLDataType.BIGINT.notNull()) + .constraints( + constraint(AUDIT_LOG_TABLE+"_pk").primaryKey(GUILD_ID_COLUMN), + constraint(AUDIT_LOG_TABLE+"_unique").unique(CHANNEL_ID_COLUMN) + ) + .execute(); - dsl.execute(createMessageLogRegistrationTable); + // create message log registration table + dsl.createTableIfNotExists(MESSAGE_LOG_REGISTRATION_TABLE) + .column(GUILD_ID_COLUMN, SQLDataType.BIGINT.notNull()) + .column(CHANNEL_ID_COLUMN, SQLDataType.BIGINT.notNull()) + .constraints( + constraint(MESSAGE_LOG_REGISTRATION_TABLE+"_pk").primaryKey(GUILD_ID_COLUMN), + constraint(MESSAGE_LOG_REGISTRATION_TABLE+"_unique").unique(CHANNEL_ID_COLUMN) + ).execute(); - String createMessageLogContentTable = String.format(""" - CREATE TABLE IF NOT EXISTS %s.%s ( - %s int8 NOT NULL, - %s text NULL, - %s int8 NOT NULL, - created_at timestamp DEFAULT (CURRENT_TIMESTAMP AT TIME ZONE 'UTC'::text) NOT NULL, - CONSTRAINT %s_pk PRIMARY KEY (%s) - ); - CREATE INDEX IF NOT EXISTS %s_created_at_idx ON %s.%s USING btree (created_at); - """, SCHEMA_NAME, MESSAGE_LOG_CONTENT_TABLE, MESSAGE_ID_COLUMN, MESSAGE_CONTENT_COLUMN, AUTHOR_ID_COLUMN, - MESSAGE_LOG_CONTENT_TABLE, MESSAGE_ID_COLUMN, - MESSAGE_LOG_CONTENT_TABLE, SCHEMA_NAME, MESSAGE_LOG_CONTENT_TABLE); + // create message log content table + dsl.createTableIfNotExists(MESSAGE_LOG_CONTENT_TABLE) + .column(MESSAGE_ID_COLUMN, SQLDataType.BIGINT.notNull()) + .column(MESSAGE_CONTENT_COLUMN, SQLDataType.CLOB.nullable(true)) + .column(AUTHOR_ID_COLUMN, SQLDataType.BIGINT.notNull()) + .column("created_at", SQLDataType.TIMESTAMP.default_(DSL.currentTimestamp()).notNull()) + .constraints( + constraint(MESSAGE_LOG_CONTENT_TABLE+"pk").primaryKey(MESSAGE_ID_COLUMN) + ) + .execute(); + // create index on created_at column + dsl.createIndexIfNotExists(MESSAGE_LOG_CONTENT_TABLE+"_created_at_idx") + .on(MESSAGE_LOG_CONTENT_TABLE, "created_at") + .execute(); - dsl.execute(createMessageLogContentTable); } } From 8ced9faba55e3757a757f2fd44ab8f2055e58564 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 31 Jul 2025 16:37:45 +0530 Subject: [PATCH 3/5] Bump version to 1.2.1 Updated the project version in pom.xml and ProjectInfo.java from 1.2.0 to 1.2.1 to reflect the latest release. --- pom.xml | 2 +- src/main/java/org/papertrail/version/ProjectInfo.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index b6667fe1..ef7f5e77 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.egg.papertrail paper-trail-bot - 1.2.0 + 1.2.1 PaperTrail A simple bot for logging all user actions diff --git a/src/main/java/org/papertrail/version/ProjectInfo.java b/src/main/java/org/papertrail/version/ProjectInfo.java index 31246d9e..cdb70a99 100644 --- a/src/main/java/org/papertrail/version/ProjectInfo.java +++ b/src/main/java/org/papertrail/version/ProjectInfo.java @@ -7,7 +7,7 @@ private ProjectInfo() { } public static final String APPNAME = "PaperTrail"; - public static final String VERSION = "v1.2.0"; + public static final String VERSION = "v1.2.1"; public static final String PROJECT_LINK = "https://github.com/Egg-03/PaperTrailBot"; public static final String PROJECT_ISSUE_LINK="https://github.com/Egg-03/PaperTrailBot/issues"; From b35abe40fdd8db43ad66b2eda63c2cc1d5cbd4ff Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 31 Jul 2025 19:00:21 +0530 Subject: [PATCH 4/5] Add daily log cleanup with pg_cron extension Introduces a setupCronDeletion method to schedule daily deletion of log entries older than 30 days using the pg_cron extension. --- .../java/org/papertrail/database/Schema.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/org/papertrail/database/Schema.java b/src/main/java/org/papertrail/database/Schema.java index 6f4b2be4..77b9573f 100644 --- a/src/main/java/org/papertrail/database/Schema.java +++ b/src/main/java/org/papertrail/database/Schema.java @@ -63,5 +63,21 @@ public static void initializeSchema(DSLContext dsl) { .on(MESSAGE_LOG_CONTENT_TABLE, "created_at") .execute(); + setupCronDeletion(dsl); + } + + private static void setupCronDeletion(DSLContext dsl) { + dsl.query("CREATE EXTENSION IF NOT EXISTS pg_cron;").execute(); + + String deleteQuery = String.format(""" + SELECT cron.schedule( + 'daily_log_cleanup', + '0 2 * * *', -- 2:00 AM UTC daily + $$DELETE FROM %s WHERE created_at < CURRENT_TIMESTAMP - INTERVAL '30 days';$$ + ); + """, MESSAGE_LOG_CONTENT_TABLE); + + dsl.query(deleteQuery).execute(); + } } From 3e8a1901e23c7cb47eb88840790fea3aa811d2f6 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+Egg-03@users.noreply.github.com> Date: Thu, 31 Jul 2025 19:34:58 +0530 Subject: [PATCH 5/5] Update Schema.java --- src/main/java/org/papertrail/database/Schema.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/papertrail/database/Schema.java b/src/main/java/org/papertrail/database/Schema.java index 77b9573f..bfaca3c6 100644 --- a/src/main/java/org/papertrail/database/Schema.java +++ b/src/main/java/org/papertrail/database/Schema.java @@ -69,7 +69,7 @@ public static void initializeSchema(DSLContext dsl) { private static void setupCronDeletion(DSLContext dsl) { dsl.query("CREATE EXTENSION IF NOT EXISTS pg_cron;").execute(); - String deleteQuery = String.format(""" + String cronScheduleQuery = String.format(""" SELECT cron.schedule( 'daily_log_cleanup', '0 2 * * *', -- 2:00 AM UTC daily @@ -77,7 +77,7 @@ private static void setupCronDeletion(DSLContext dsl) { ); """, MESSAGE_LOG_CONTENT_TABLE); - dsl.query(deleteQuery).execute(); + dsl.query(cronScheduleQuery).execute(); } }