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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -225,3 +225,4 @@ buildNumber.properties
# Custom
.idea/discord.xml
.env
/.idea
17 changes: 16 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,21 @@
<artifactId>dotenv-java</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>6.3.0</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.7.7</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.20.5</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
Expand All @@ -57,7 +67,12 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.81</version>
</dependency>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.4.8-jre</version>
</dependency>
</dependencies>

<build>
Expand Down
32 changes: 17 additions & 15 deletions src/main/java/org/papertrail/cleanup/BotKickListener.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
package org.papertrail.cleanup;

import java.sql.SQLException;

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;

public BotKickListener(DatabaseConnector dc) {
this.dc=dc;

private final Executor vThreadPool;
private final DatabaseConnector dc;

public BotKickListener(DatabaseConnector dc, Executor vThreadPool) {
this.dc = dc;
this.vThreadPool = vThreadPool;
}

@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());
}
vThreadPool.execute(()->{
dc.getGuildDataAccess().unregister(leftGuild.getId(), TableNames.AUDIT_LOG_TABLE);
dc.getGuildDataAccess().unregister(leftGuild.getId(), TableNames.MESSAGE_LOG_REGISTRATION_TABLE);
});

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.papertrail.database;

public record AuthorAndMessageEntity(String authorId, String messageContent) {


}
244 changes: 32 additions & 212 deletions src/main/java/org/papertrail/database/DatabaseConnector.java
Original file line number Diff line number Diff line change
@@ -1,231 +1,51 @@
package org.papertrail.database;

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;

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;

private Connection connect;

public DatabaseConnector() throws SQLException {
connect = DriverManager.getConnection(DB_URL);
public DatabaseConnector() {
initializeDataSource();
this.dsl = DSL.using(dataSource, SQLDialect.POSTGRES);
}

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 GuildDataAccess getGuildDataAccess() {
return new GuildDataAccess(dsl);
}

public List<String> retrieveAllRegisteredGuilds(String tableName) {

String sqlStatement = "SELECT guild_id FROM " + tableName;
List<String> 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();
}
public MessageDataAccess getMessageDataAccess() {
return new MessageDataAccess(dsl);
}

public List<String> retrieveAllRegisteredChannels(String tableName) {

String sqlStatement = "SELECT channel_id FROM " + tableName;
List<String> channels = new ArrayList<>();
private static synchronized void initializeDataSource() {

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();
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.");
}
}));
}

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 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<String> 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 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();
}
}

}
Loading
Loading