diff --git a/pom.xml b/pom.xml
index 3aed105..870c215 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,14 +6,16 @@
wtf.beatrice.hidekobot
HidekoBot
- 0.6.3-SNAPSHOT
+ 0.9.0-SNAPSHOT
21
21
UTF-8
- ./target/dependency-check-report.html
- ./target/dependency-check-report.json
+ ./target/dependency-check-report.html
+
+ ./target/dependency-check-report.json
+
true
@@ -30,11 +32,6 @@
slf4j-api
2.0.17
-
- org.slf4j
- slf4j-simple
- 2.0.17
-
@@ -95,27 +92,10 @@
test
-
-
- org.springframework
- spring-context
- 6.2.7
-
-
- org.springframework
- spring-tx
- 6.2.7
-
-
- org.springframework
- spring-orm
- 6.2.7
-
-
- org.springframework.data
- spring-data-jpa
- 3.3.4
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+ 3.4.5
@@ -159,29 +139,6 @@
-
- org.apache.maven.plugins
- maven-assembly-plugin
-
-
- package
-
- single
-
-
-
-
- wtf.beatrice.hidekobot.HidekoBot
-
-
-
- jar-with-dependencies
-
-
-
-
-
-
org.apache.maven.plugins
maven-javadoc-plugin
@@ -202,7 +159,9 @@
8
${nvdApiKey}
- https://raw.githubusercontent.com/EugenMayer/cisa-known-exploited-mirror/main/known_exploited_vulnerabilities.json
+
+ https://raw.githubusercontent.com/EugenMayer/cisa-known-exploited-mirror/main/known_exploited_vulnerabilities.json
+
html
json
@@ -213,6 +172,19 @@
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ 3.4.5
+
+
+
+ repackage
+
+
+
+
+
diff --git a/src/main/java/wtf/beatrice/hidekobot/Cache.java b/src/main/java/wtf/beatrice/hidekobot/Cache.java
index 7a1385e..35398fb 100644
--- a/src/main/java/wtf/beatrice/hidekobot/Cache.java
+++ b/src/main/java/wtf/beatrice/hidekobot/Cache.java
@@ -5,12 +5,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import wtf.beatrice.hidekobot.datasources.ConfigurationEntry;
import wtf.beatrice.hidekobot.datasources.ConfigurationSource;
-import wtf.beatrice.hidekobot.datasources.DatabaseSource;
import wtf.beatrice.hidekobot.datasources.PropertiesSource;
import wtf.beatrice.hidekobot.listeners.MessageCommandListener;
import wtf.beatrice.hidekobot.listeners.MessageLogger;
import wtf.beatrice.hidekobot.listeners.SlashCommandCompletionListener;
import wtf.beatrice.hidekobot.listeners.SlashCommandListener;
+import wtf.beatrice.hidekobot.util.Services;
import java.awt.*;
import java.lang.reflect.Field;
@@ -27,11 +27,22 @@ public class Cache
throw new IllegalStateException("Utility class");
}
-
// todo: make this compatible with the message listener's regex
private static final String BOT_PREFIX = "hideko";
private static final Logger LOGGER = LoggerFactory.getLogger(Cache.class);
+ private static Services SERVICES;
+
+ public static void setServices(Services services)
+ {
+ SERVICES = services;
+ }
+
+ public static Services getServices()
+ {
+ return SERVICES;
+ }
+
// map to store results of "love calculator", to avoid people re-running the same command until
// they get what they wanted.
// i didn't think this was worthy of a whole database table with a runnable checking for expiration,
@@ -40,7 +51,6 @@ public class Cache
private static PropertiesSource propertiesSource = null;
private static ConfigurationSource configurationSource = null;
- private static DatabaseSource databaseSource = null;
private static boolean verbose = false;
private static MessageLogger verbosityLogger = null;
private static final long BOT_MAINTAINER_ID = 979809420714332260L;
@@ -181,26 +191,6 @@ public class Cache
return DEFAULT_INVITE_LINK.replace("%userid%", botApplicationId);
}
- /**
- * Set the already fully-initialized DatabaseSource instance, ready to be accessed and used.
- *
- * @param databaseSourceInstance the fully-initialized DatabaseSource instance.
- */
- public static void setDatabaseSourceInstance(DatabaseSource databaseSourceInstance)
- {
- databaseSource = databaseSourceInstance;
- }
-
- /**
- * Get the fully-initialized DatabaseSource instance, ready to be used.
- *
- * @return the DatabaseSource instance.
- */
- public static @Nullable DatabaseSource getDatabaseSource()
- {
- return databaseSource;
- }
-
/**
* Set the properties source instance loaded from the JAR archive.
*
diff --git a/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java b/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java
index cffb67e..80f9693 100644
--- a/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java
+++ b/src/main/java/wtf/beatrice/hidekobot/HidekoBot.java
@@ -6,20 +6,24 @@ import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.requests.GatewayIntent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.ConfigurableApplicationContext;
import wtf.beatrice.hidekobot.commands.completer.ProfileImageCommandCompleter;
import wtf.beatrice.hidekobot.commands.message.HelloCommand;
import wtf.beatrice.hidekobot.commands.slash.*;
import wtf.beatrice.hidekobot.datasources.ConfigurationSource;
-import wtf.beatrice.hidekobot.datasources.DatabaseSource;
import wtf.beatrice.hidekobot.datasources.PropertiesSource;
import wtf.beatrice.hidekobot.listeners.*;
import wtf.beatrice.hidekobot.runnables.ExpiredMessageTask;
import wtf.beatrice.hidekobot.runnables.HeartBeatTask;
import wtf.beatrice.hidekobot.runnables.RandomOrgSeedTask;
import wtf.beatrice.hidekobot.runnables.StatusUpdateTask;
+import wtf.beatrice.hidekobot.services.DatabaseService;
import wtf.beatrice.hidekobot.util.CommandUtil;
import wtf.beatrice.hidekobot.util.FormatUtil;
import wtf.beatrice.hidekobot.util.RandomUtil;
+import wtf.beatrice.hidekobot.util.Services;
import java.io.File;
import java.time.LocalDateTime;
@@ -30,6 +34,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
+@SpringBootApplication
public class HidekoBot
{
private static JDA jda;
@@ -63,6 +68,16 @@ public class HidekoBot
return;
}
+ ConfigurableApplicationContext context = SpringApplication.run(HidekoBot.class, args);
+
+ CommandUtil commandUtil = context.getBean(CommandUtil.class);
+ DatabaseService databaseService = context.getBean(DatabaseService.class);
+ Services services = new wtf.beatrice.hidekobot.util.Services(
+ commandUtil,
+ databaseService
+ );
+ Cache.setServices(services);
+
try
{
// try to create the bot object and authenticate it with discord.
@@ -114,7 +129,6 @@ public class HidekoBot
}
-
boolean enableRandomSeedUpdaterTask = false;
// initialize random.org object if API key is provided
{
@@ -128,8 +142,11 @@ public class HidekoBot
}
// register slash commands and completers
- SlashCommandListener slashCommandListener = new SlashCommandListener();
- SlashCommandCompletionListener slashCommandCompletionListener = new SlashCommandCompletionListener();
+ SlashCommandListener slashCommandListener = context.getBean(SlashCommandListener.class);
+ SlashCommandCompletionListener slashCommandCompletionListener = context.getBean(SlashCommandCompletionListener.class);
+ MessageCommandListener messageCommandListener = context.getBean(MessageCommandListener.class);
+ ButtonInteractionListener buttonInteractionListener = context.getBean(ButtonInteractionListener.class);
+ SelectMenuInteractionListener selectMenuInteractionListener = context.getBean(SelectMenuInteractionListener.class);
AvatarCommand avatarCommand = new AvatarCommand();
ProfileImageCommandCompleter avatarCommandCompleter = new ProfileImageCommandCompleter(avatarCommand);
slashCommandListener.registerCommand(avatarCommand);
@@ -156,7 +173,6 @@ public class HidekoBot
slashCommandListener.registerCommand(new UrbanDictionaryCommand());
// register message commands
- MessageCommandListener messageCommandListener = new MessageCommandListener();
messageCommandListener.registerCommand(new HelloCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.AliasCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.AvatarCommand());
@@ -183,43 +199,28 @@ public class HidekoBot
jda.addEventListener(messageCommandListener);
jda.addEventListener(slashCommandListener);
jda.addEventListener(slashCommandCompletionListener);
- jda.addEventListener(new ButtonInteractionListener());
- jda.addEventListener(new SelectMenuInteractionListener());
+ jda.addEventListener(buttonInteractionListener);
+ jda.addEventListener(selectMenuInteractionListener);
// update slash commands (delayed)
final boolean finalForceUpdateCommands = forceUpdateCommands;
try (ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor())
{
- executor.schedule(() -> CommandUtil.updateSlashCommands(finalForceUpdateCommands),
+ executor.schedule(() -> commandUtil.updateSlashCommands(finalForceUpdateCommands),
1, TimeUnit.SECONDS);
}
// set the bot's status
jda.getPresence().setStatus(OnlineStatus.ONLINE);
- // connect to database
- LOGGER.info("Connecting to database...");
- String dbFilePath = Cache.getExecPath() + File.separator + "db.sqlite"; // in current directory
- DatabaseSource databaseSource = new DatabaseSource(dbFilePath);
- if (databaseSource.connect() && databaseSource.initDb())
- {
- LOGGER.info("Database connection initialized!");
- Cache.setDatabaseSourceInstance(databaseSource);
-
- // load data here...
-
- LOGGER.info("Database data loaded into memory!");
- } else
- {
- LOGGER.error("Error initializing database connection!");
- }
-
// start scheduled runnables
ScheduledExecutorService scheduler = Cache.getTaskScheduler();
- ExpiredMessageTask expiredMessageTask = new ExpiredMessageTask();
+ ExpiredMessageTask expiredMessageTask = new ExpiredMessageTask(services.databaseService(), services.commandUtil());
scheduler.scheduleAtFixedRate(expiredMessageTask, 5L, 5L, TimeUnit.SECONDS); //every 5 seconds
+
HeartBeatTask heartBeatTask = new HeartBeatTask();
scheduler.scheduleAtFixedRate(heartBeatTask, 10L, 30L, TimeUnit.SECONDS); //every 30 seconds
+
StatusUpdateTask statusUpdateTask = new StatusUpdateTask();
scheduler.scheduleAtFixedRate(statusUpdateTask, 0L, 60L * 5L, TimeUnit.SECONDS); // every 5 minutes
if (enableRandomSeedUpdaterTask)
diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/base/CoinFlip.java b/src/main/java/wtf/beatrice/hidekobot/commands/base/CoinFlip.java
index 2ce7cbd..945c9c1 100644
--- a/src/main/java/wtf/beatrice/hidekobot/commands/base/CoinFlip.java
+++ b/src/main/java/wtf/beatrice/hidekobot/commands/base/CoinFlip.java
@@ -44,7 +44,7 @@ public class CoinFlip
public static void buttonReFlip(ButtonInteractionEvent event)
{
// check if the user interacting is the same one who ran the command
- if (!(Cache.getDatabaseSource().isUserTrackedFor(event.getUser().getId(), event.getMessageId())))
+ if (!(Cache.getServices().databaseService().isUserTrackedFor(event.getUser().getId(), event.getMessageId())))
{
event.reply("❌ You did not run this command!").setEphemeral(true).queue();
return;
@@ -68,7 +68,7 @@ public class CoinFlip
public static void trackAndRestrict(Message replyMessage, User user)
{
- Cache.getDatabaseSource().queueDisabling(replyMessage);
- Cache.getDatabaseSource().trackRanCommandReply(replyMessage, user);
+ Cache.getServices().databaseService().queueDisabling(replyMessage);
+ Cache.getServices().databaseService().trackRanCommandReply(replyMessage, user);
}
}
diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/base/Trivia.java b/src/main/java/wtf/beatrice/hidekobot/commands/base/Trivia.java
index f0b305a..bbd8fd4 100644
--- a/src/main/java/wtf/beatrice/hidekobot/commands/base/Trivia.java
+++ b/src/main/java/wtf/beatrice/hidekobot/commands/base/Trivia.java
@@ -19,7 +19,6 @@ import wtf.beatrice.hidekobot.objects.fun.TriviaCategory;
import wtf.beatrice.hidekobot.objects.fun.TriviaQuestion;
import wtf.beatrice.hidekobot.objects.fun.TriviaScore;
import wtf.beatrice.hidekobot.runnables.TriviaTask;
-import wtf.beatrice.hidekobot.util.CommandUtil;
import java.io.BufferedReader;
import java.io.IOException;
@@ -253,14 +252,14 @@ public class Trivia
public static void handleMenuSelection(StringSelectInteractionEvent event)
{
// check if the user interacting is the same one who ran the command
- if (!(Cache.getDatabaseSource().isUserTrackedFor(event.getUser().getId(), event.getMessageId())))
+ if (!(Cache.getServices().databaseService().isUserTrackedFor(event.getUser().getId(), event.getMessageId())))
{
event.reply("❌ You did not run this command!").setEphemeral(true).queue();
return;
}
// todo: we shouldn't use this method, since it messes with the database... look at coin reflip
- CommandUtil.disableExpired(event.getMessageId());
+ Cache.getServices().commandUtil().disableExpired(event.getMessageId());
SelectOption pickedOption = event.getInteraction().getSelectedOptions().get(0);
String categoryName = pickedOption.getLabel();
@@ -293,7 +292,8 @@ public class Trivia
}
- TriviaTask triviaTask = new TriviaTask(author, channel, category);
+ TriviaTask triviaTask = new TriviaTask(author, channel, category,
+ Cache.getServices().databaseService(), Cache.getServices().commandUtil());
ScheduledFuture> future =
Cache.getTaskScheduler().scheduleAtFixedRate(triviaTask,
0,
diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/base/UrbanDictionary.java b/src/main/java/wtf/beatrice/hidekobot/commands/base/UrbanDictionary.java
index 0903f87..887f236 100644
--- a/src/main/java/wtf/beatrice/hidekobot/commands/base/UrbanDictionary.java
+++ b/src/main/java/wtf/beatrice/hidekobot/commands/base/UrbanDictionary.java
@@ -14,7 +14,7 @@ import org.apache.commons.text.WordUtils;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import wtf.beatrice.hidekobot.Cache;
-import wtf.beatrice.hidekobot.datasources.DatabaseSource;
+import wtf.beatrice.hidekobot.services.DatabaseService;
import wtf.beatrice.hidekobot.util.SerializationUtil;
import java.util.ArrayList;
@@ -107,9 +107,9 @@ public class UrbanDictionary
public static void track(Message message, User user, UrbanSearch search, String sanitizedTerm)
{
- Cache.getDatabaseSource().queueDisabling(message);
- Cache.getDatabaseSource().trackRanCommandReply(message, user);
- Cache.getDatabaseSource().trackUrban(search.getSerializedMeanings(),
+ Cache.getServices().databaseService().queueDisabling(message);
+ Cache.getServices().databaseService().trackRanCommandReply(message, user);
+ Cache.getServices().databaseService().trackUrban(search.getSerializedMeanings(),
search.getSerializedExamples(),
search.getSerializedContributors(),
search.getSerializedDates(),
@@ -120,7 +120,7 @@ public class UrbanDictionary
public static void changePage(ButtonInteractionEvent event, ChangeType changeType)
{
String messageId = event.getMessageId();
- DatabaseSource database = Cache.getDatabaseSource();
+ DatabaseService database = Cache.getServices().databaseService();
// check if the user interacting is the same one who ran the command
if (!(database.isUserTrackedFor(event.getUser().getId(), messageId)))
@@ -130,7 +130,7 @@ public class UrbanDictionary
}
// get current page and calculate how many pages there are
- int page = Cache.getDatabaseSource().getUrbanPage(messageId);
+ int page = database.getUrbanPage(messageId);
String term = database.getUrbanTerm(messageId);
String url = generateUrl(term);
diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/message/ClearCommand.java b/src/main/java/wtf/beatrice/hidekobot/commands/message/ClearCommand.java
index a5c5349..2c8318a 100644
--- a/src/main/java/wtf/beatrice/hidekobot/commands/message/ClearCommand.java
+++ b/src/main/java/wtf/beatrice/hidekobot/commands/message/ClearCommand.java
@@ -108,8 +108,8 @@ public class ClearCommand implements MessageCommand
Message finalMessage = event.getChannel().sendMessage(content).setActionRow(dismiss).complete();
// add the message to database.
- Cache.getDatabaseSource().queueDisabling(finalMessage);
- Cache.getDatabaseSource().trackRanCommandReply(finalMessage, event.getAuthor());
+ Cache.getServices().databaseService().queueDisabling(finalMessage);
+ Cache.getServices().databaseService().trackRanCommandReply(finalMessage, event.getAuthor());
// delete the sender's message.
event.getMessage().delete().queue();
diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/message/TriviaCommand.java b/src/main/java/wtf/beatrice/hidekobot/commands/message/TriviaCommand.java
index 50fff25..7b93a93 100644
--- a/src/main/java/wtf/beatrice/hidekobot/commands/message/TriviaCommand.java
+++ b/src/main/java/wtf/beatrice/hidekobot/commands/message/TriviaCommand.java
@@ -94,8 +94,8 @@ public class TriviaCommand implements MessageCommand
if (response.components() != null) responseAction = responseAction.addActionRow(response.components());
responseAction.queue(message -> {
- Cache.getDatabaseSource().trackRanCommandReply(message, event.getAuthor());
- Cache.getDatabaseSource().queueDisabling(message);
+ Cache.getServices().databaseService().trackRanCommandReply(message, event.getAuthor());
+ Cache.getServices().databaseService().queueDisabling(message);
});
}
diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/slash/ClearCommand.java b/src/main/java/wtf/beatrice/hidekobot/commands/slash/ClearCommand.java
index 528f1ae..420db6a 100644
--- a/src/main/java/wtf/beatrice/hidekobot/commands/slash/ClearCommand.java
+++ b/src/main/java/wtf/beatrice/hidekobot/commands/slash/ClearCommand.java
@@ -72,8 +72,8 @@ public class ClearCommand extends SlashCommandImpl
botMessage = botMessage.editMessage(content).setActionRow(dismiss).complete();
// add the message to database.
- Cache.getDatabaseSource().queueDisabling(botMessage);
- Cache.getDatabaseSource().trackRanCommandReply(botMessage, event.getUser());
+ Cache.getServices().databaseService().queueDisabling(botMessage);
+ Cache.getServices().databaseService().trackRanCommandReply(botMessage, event.getUser());
}
}
diff --git a/src/main/java/wtf/beatrice/hidekobot/commands/slash/TriviaCommand.java b/src/main/java/wtf/beatrice/hidekobot/commands/slash/TriviaCommand.java
index 8730881..0c39104 100644
--- a/src/main/java/wtf/beatrice/hidekobot/commands/slash/TriviaCommand.java
+++ b/src/main/java/wtf/beatrice/hidekobot/commands/slash/TriviaCommand.java
@@ -44,8 +44,8 @@ public class TriviaCommand extends SlashCommandImpl
event.getHook().editOriginalEmbeds(response.embed()).setActionRow(response.components()).queue(message ->
{
- Cache.getDatabaseSource().trackRanCommandReply(message, event.getUser());
- Cache.getDatabaseSource().queueDisabling(message);
+ Cache.getServices().databaseService().trackRanCommandReply(message, event.getUser());
+ Cache.getServices().databaseService().queueDisabling(message);
});
}
}
diff --git a/src/main/java/wtf/beatrice/hidekobot/datasources/DatabaseSource.java b/src/main/java/wtf/beatrice/hidekobot/datasources/DatabaseSource.java
deleted file mode 100644
index fc52343..0000000
--- a/src/main/java/wtf/beatrice/hidekobot/datasources/DatabaseSource.java
+++ /dev/null
@@ -1,682 +0,0 @@
-package wtf.beatrice.hidekobot.datasources;
-
-import net.dv8tion.jda.api.entities.Message;
-import net.dv8tion.jda.api.entities.User;
-import net.dv8tion.jda.api.entities.channel.ChannelType;
-import org.slf4j.LoggerFactory;
-import wtf.beatrice.hidekobot.Cache;
-
-import java.sql.*;
-import java.time.LocalDateTime;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.List;
-
-public class DatabaseSource
-{
-
- private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(DatabaseSource.class);
- private static final String JDBC_URL = "jdbc:sqlite:%path%";
- private Connection dbConnection = null;
- private final String dbPath;
-
- public DatabaseSource(String dbPath)
- {
- this.dbPath = dbPath;
- }
-
- private void logException(SQLException e)
- {
- LOGGER.error("Database Exception", e);
- }
-
- public boolean connect()
- {
- String url = JDBC_URL.replace("%path%", dbPath);
-
- if (!close()) return false;
-
- try
- {
- dbConnection = DriverManager.getConnection(url);
- LOGGER.info("Database connection established!");
- return true;
- } catch (SQLException e)
- {
- logException(e);
- return false;
- }
-
- }
-
-
- public boolean close()
- {
- if (dbConnection != null)
- {
- try
- {
- if (!dbConnection.isClosed())
- {
- dbConnection.close();
- }
- } catch (SQLException e)
- {
- logException(e);
- return false;
- }
-
- dbConnection = null;
- }
-
- return true;
- }
-
- /*
- * DB STRUCTURE
- * TABLE 1: pending_disabled_messages
- * ----------------------------------------------------------------------------------
- * | guild_id | channel_id | message_id | expiry_timestamp |
- * ----------------------------------------------------------------------------------
- * |39402849302 | 39402849302 | 39402849302 | 2022-11-20 22:45:53:300 |
- * ---------------------------------------------------------------------------------
- *
- *
- * TABLE 2: command_runners
- * --------------------------------------------------------------------------------------------
- * | guild_id | channel_id | message_id | user_id | channel_type |
- * --------------------------------------------------------------------------------------------
- * | 39402849302 | 39402849302 | 39402849302 | 39402849302 | PRIVATE |
- * --------------------------------------------------------------------------------------------
- *
- * TABLE 3: urban_dictionary
- * -----------------------------------------------------------------------------------------------------
- * | message_id | page | meanings | examples | contributors | dates | term |
- * -----------------------------------------------------------------------------------------------------
- * | 39402849302 | 0 | base64 | base64 | base64 | base64 | miku |
- * -----------------------------------------------------------------------------------------------------
- */
-
- //todo: javadocs
- public boolean initDb()
- {
- List newTables = new ArrayList<>();
-
- newTables.add("""
- CREATE TABLE IF NOT EXISTS pending_disabled_messages (
- guild_id TEXT NOT NULL,
- channel_id TEXT NOT NULL,
- message_id TEXT NOT NULL,
- expiry_timestamp TEXT NOT NULL);
- """);
-
- newTables.add("""
- CREATE TABLE IF NOT EXISTS command_runners (
- guild_id TEXT NOT NULL,
- channel_id TEXT NOT NULL,
- message_id TEXT NOT NULL,
- user_id TEXT NOT NULL,
- channel_type TEXT NOT NULL);
- """);
-
- newTables.add("""
- CREATE TABLE IF NOT EXISTS urban_dictionary (
- message_id TEXT NOT NULL,
- page INTEGER NOT NULL,
- meanings TEXT NOT NULL,
- examples TEXT NOT NULL,
- contributors TEXT NOT NULL,
- dates TEXT NOT NULL,
- term TEXT NOT NULL
- );
- """);
-
- for (String sql : newTables)
- {
- try (Statement stmt = dbConnection.createStatement())
- {
- // execute the statement
- stmt.execute(sql);
- } catch (SQLException e)
- {
- logException(e);
- return false;
- }
- }
-
- return true;
- }
-
- public boolean trackRanCommandReply(Message message, User user)
- {
- String userId = user.getId();
- String guildId;
-
- ChannelType channelType = message.getChannelType();
- if (!(channelType.isGuild()))
- {
- guildId = userId;
- } else
- {
- guildId = message.getGuild().getId();
- }
-
- String channelId = message.getChannel().getId();
- String messageId = message.getId();
-
-
- String query = """
- INSERT INTO command_runners
- (guild_id, channel_id, message_id, user_id, channel_type) VALUES
- (?, ?, ?, ?, ?);
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, guildId);
- preparedStatement.setString(2, channelId);
- preparedStatement.setString(3, messageId);
- preparedStatement.setString(4, userId);
- preparedStatement.setString(5, channelType.name());
-
- preparedStatement.executeUpdate();
-
- return true;
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return false;
- }
-
- public boolean isUserTrackedFor(String userId, String messageId)
- {
- String trackedUserId = getTrackedReplyUserId(messageId);
- if (trackedUserId == null) return false;
- return userId.equals(trackedUserId);
- }
-
- public ChannelType getTrackedMessageChannelType(String messageId)
- {
- String query = """
- SELECT channel_type
- FROM command_runners
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- String channelTypeName = resultSet.getString("channel_type");
- return ChannelType.valueOf(channelTypeName);
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
-
- }
-
- public String getTrackedReplyUserId(String messageId)
- {
- String query = """
- SELECT user_id
- FROM command_runners
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- return resultSet.getString("user_id");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
- }
-
- public boolean queueDisabling(Message message)
- {
- String messageId = message.getId();
- String channelId = message.getChannel().getId();
- String guildId;
-
- ChannelType channelType = message.getChannelType();
- if (!(channelType.isGuild()))
- {
- guildId = "PRIVATE";
- } else
- {
- guildId = message.getGuild().getId();
- }
-
- LocalDateTime expiryTime = LocalDateTime.now().plusSeconds(Cache.getExpiryTimeSeconds());
-
- DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(Cache.getExpiryTimestampFormat());
- String expiryTimeFormatted = dateTimeFormatter.format(expiryTime);
-
- String query = """
- INSERT INTO pending_disabled_messages
- (guild_id, channel_id, message_id, expiry_timestamp) VALUES
- (?, ?, ?, ?);
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, guildId);
- preparedStatement.setString(2, channelId);
- preparedStatement.setString(3, messageId);
- preparedStatement.setString(4, expiryTimeFormatted);
-
- preparedStatement.executeUpdate();
-
- return true;
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return false;
- }
-
- public List getQueuedExpiringMessages()
- {
- List messages = new ArrayList<>();
-
- String query = """
- SELECT message_id
- FROM pending_disabled_messages;
- """;
-
- try (Statement statement = dbConnection.createStatement())
- {
- ResultSet resultSet = statement.executeQuery(query);
- if (resultSet.isClosed()) return messages;
- while (resultSet.next())
- {
- messages.add(resultSet.getString("message_id"));
- }
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return messages;
- }
-
- public boolean untrackExpiredMessage(String messageId)
- {
- String query = "DELETE FROM pending_disabled_messages WHERE message_id = ?;";
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- preparedStatement.execute();
- } catch (SQLException e)
- {
- logException(e);
- return false;
- }
-
- query = "DELETE FROM command_runners WHERE message_id = ?;";
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- preparedStatement.execute();
- } catch (SQLException e)
- {
- logException(e);
- return false;
- }
-
- query = "DELETE FROM urban_dictionary WHERE message_id = ?;";
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- preparedStatement.execute();
- } catch (SQLException e)
- {
- logException(e);
- return false;
- }
-
- return true;
- }
-
- public String getQueuedExpiringMessageExpiryDate(String messageId)
- {
- String query = """
- SELECT expiry_timestamp
- FROM pending_disabled_messages
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- return resultSet.getString("expiry_timestamp");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
- }
-
- public String getQueuedExpiringMessageChannel(String messageId)
- {
- String query = """
- SELECT channel_id
- FROM pending_disabled_messages
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- return resultSet.getString("channel_id");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
- }
-
- public String getQueuedExpiringMessageGuild(String messageId)
- {
- String query = """
- SELECT guild_id
- FROM pending_disabled_messages
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- return resultSet.getString("guild_id");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
- }
-
- public boolean trackUrban(String meanings, String examples,
- String contributors, String dates,
- Message message, String term)
- {
-
- String query = """
- INSERT INTO urban_dictionary
- (message_id, page, meanings, examples, contributors, dates, term) VALUES
- (?, ?, ?, ?, ?, ?, ?);
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, message.getId());
- preparedStatement.setInt(2, 0);
- preparedStatement.setString(3, meanings);
- preparedStatement.setString(4, examples);
- preparedStatement.setString(5, contributors);
- preparedStatement.setString(6, dates);
- preparedStatement.setString(7, term);
-
- preparedStatement.executeUpdate();
-
- return true;
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return false;
- }
-
- public int getUrbanPage(String messageId)
- {
- String query = """
- SELECT page
- FROM urban_dictionary
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return 0;
- while (resultSet.next())
- {
- return resultSet.getInt("page");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return 0;
- }
-
- public String getUrbanMeanings(String messageId)
- {
- String query = """
- SELECT meanings
- FROM urban_dictionary
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- return resultSet.getString("meanings");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
- }
-
- public String getUrbanExamples(String messageId)
- {
- String query = """
- SELECT examples
- FROM urban_dictionary
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- return resultSet.getString("examples");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
- }
-
- public String getUrbanContributors(String messageId)
- {
- String query = """
- SELECT contributors
- FROM urban_dictionary
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- return resultSet.getString("contributors");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
- }
-
- public String getUrbanDates(String messageId)
- {
- String query = """
- SELECT dates
- FROM urban_dictionary
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- return resultSet.getString("dates");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
- }
-
- public String getUrbanTerm(String messageId)
- {
- String query = """
- SELECT term
- FROM urban_dictionary
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, messageId);
- ResultSet resultSet = preparedStatement.executeQuery();
- if (resultSet.isClosed()) return null;
- while (resultSet.next())
- {
- return resultSet.getString("term");
- }
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return null;
- }
-
- public boolean setUrbanPage(String messageId, int page)
- {
- String query = """
- UPDATE urban_dictionary
- SET page = ?
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setInt(1, page);
- preparedStatement.setString(2, messageId);
- preparedStatement.executeUpdate();
-
- return true;
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return false;
- }
-
- public boolean resetExpiryTimestamp(String messageId)
- {
- LocalDateTime expiryTime = LocalDateTime.now().plusSeconds(Cache.getExpiryTimeSeconds());
-
- DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(Cache.getExpiryTimestampFormat());
- String expiryTimeFormatted = dateTimeFormatter.format(expiryTime);
-
- String query = """
- UPDATE pending_disabled_messages
- SET expiry_timestamp = ?
- WHERE message_id = ?;
- """;
-
- try (PreparedStatement preparedStatement = dbConnection.prepareStatement(query))
- {
- preparedStatement.setString(1, expiryTimeFormatted);
- preparedStatement.setString(2, messageId);
- preparedStatement.executeUpdate();
-
- return true;
-
- } catch (SQLException e)
- {
- logException(e);
- }
-
- return false;
- }
-
-
-}
diff --git a/src/main/java/wtf/beatrice/hidekobot/entities/UrbanDictionaryEntry.java b/src/main/java/wtf/beatrice/hidekobot/entities/UrbanDictionaryEntry.java
index b747053..16c2794 100644
--- a/src/main/java/wtf/beatrice/hidekobot/entities/UrbanDictionaryEntry.java
+++ b/src/main/java/wtf/beatrice/hidekobot/entities/UrbanDictionaryEntry.java
@@ -30,4 +30,74 @@ public class UrbanDictionaryEntry
@Column(name = "term", nullable = false)
private String term;
+
+ public String getMessageId()
+ {
+ return messageId;
+ }
+
+ public void setMessageId(String messageId)
+ {
+ this.messageId = messageId;
+ }
+
+ public Integer getPage()
+ {
+ return page;
+ }
+
+ public void setPage(Integer page)
+ {
+ this.page = page;
+ }
+
+ public String getMeanings()
+ {
+ return meanings;
+ }
+
+ public void setMeanings(String meanings)
+ {
+ this.meanings = meanings;
+ }
+
+ public String getExamples()
+ {
+ return examples;
+ }
+
+ public void setExamples(String examples)
+ {
+ this.examples = examples;
+ }
+
+ public String getContributors()
+ {
+ return contributors;
+ }
+
+ public void setContributors(String contributors)
+ {
+ this.contributors = contributors;
+ }
+
+ public String getDates()
+ {
+ return dates;
+ }
+
+ public void setDates(String dates)
+ {
+ this.dates = dates;
+ }
+
+ public String getTerm()
+ {
+ return term;
+ }
+
+ public void setTerm(String term)
+ {
+ this.term = term;
+ }
}
diff --git a/src/main/java/wtf/beatrice/hidekobot/listeners/ButtonInteractionListener.java b/src/main/java/wtf/beatrice/hidekobot/listeners/ButtonInteractionListener.java
index 22c057b..37343ec 100644
--- a/src/main/java/wtf/beatrice/hidekobot/listeners/ButtonInteractionListener.java
+++ b/src/main/java/wtf/beatrice/hidekobot/listeners/ButtonInteractionListener.java
@@ -4,16 +4,24 @@ import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.CoinFlip;
import wtf.beatrice.hidekobot.commands.base.Trivia;
import wtf.beatrice.hidekobot.commands.base.UrbanDictionary;
import wtf.beatrice.hidekobot.util.CommandUtil;
+@Component
public class ButtonInteractionListener extends ListenerAdapter
{
-
private static final Logger LOGGER = LoggerFactory.getLogger(ButtonInteractionListener.class);
+ private final CommandUtil commandUtil;
+
+ public ButtonInteractionListener(CommandUtil commandUtil)
+ {
+ this.commandUtil = commandUtil;
+ }
+
@Override
public void onButtonInteraction(ButtonInteractionEvent event)
{
@@ -25,7 +33,7 @@ public class ButtonInteractionListener extends ListenerAdapter
case "coinflip_reflip" -> CoinFlip.buttonReFlip(event);
// generic dismiss button
- case "generic_dismiss" -> CommandUtil.delete(event);
+ case "generic_dismiss" -> commandUtil.delete(event);
// urban dictionary navigation
case "urban_nextpage" -> UrbanDictionary.changePage(event, UrbanDictionary.ChangeType.NEXT);
diff --git a/src/main/java/wtf/beatrice/hidekobot/listeners/MessageCommandListener.java b/src/main/java/wtf/beatrice/hidekobot/listeners/MessageCommandListener.java
index ea105c4..b7d0b58 100644
--- a/src/main/java/wtf/beatrice/hidekobot/listeners/MessageCommandListener.java
+++ b/src/main/java/wtf/beatrice/hidekobot/listeners/MessageCommandListener.java
@@ -7,6 +7,7 @@ import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -14,6 +15,7 @@ import wtf.beatrice.hidekobot.objects.comparators.MessageCommandAliasesComparato
import java.util.*;
+@Component
public class MessageCommandListener extends ListenerAdapter
{
diff --git a/src/main/java/wtf/beatrice/hidekobot/listeners/MessageLogger.java b/src/main/java/wtf/beatrice/hidekobot/listeners/MessageLogger.java
index e747150..9ccbdb7 100644
--- a/src/main/java/wtf/beatrice/hidekobot/listeners/MessageLogger.java
+++ b/src/main/java/wtf/beatrice/hidekobot/listeners/MessageLogger.java
@@ -8,7 +8,9 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+@Component
public class MessageLogger extends ListenerAdapter
{
// this class only gets loaded as a listener if verbosity is set to true on startup.
diff --git a/src/main/java/wtf/beatrice/hidekobot/listeners/SelectMenuInteractionListener.java b/src/main/java/wtf/beatrice/hidekobot/listeners/SelectMenuInteractionListener.java
index 2afc5c8..bf31dca 100644
--- a/src/main/java/wtf/beatrice/hidekobot/listeners/SelectMenuInteractionListener.java
+++ b/src/main/java/wtf/beatrice/hidekobot/listeners/SelectMenuInteractionListener.java
@@ -4,8 +4,10 @@ import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionE
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.Trivia;
+@Component
public class SelectMenuInteractionListener extends ListenerAdapter
{
diff --git a/src/main/java/wtf/beatrice/hidekobot/listeners/SlashCommandCompletionListener.java b/src/main/java/wtf/beatrice/hidekobot/listeners/SlashCommandCompletionListener.java
index ee5f97e..16e0418 100644
--- a/src/main/java/wtf/beatrice/hidekobot/listeners/SlashCommandCompletionListener.java
+++ b/src/main/java/wtf/beatrice/hidekobot/listeners/SlashCommandCompletionListener.java
@@ -2,11 +2,13 @@ package wtf.beatrice.hidekobot.listeners;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
+import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.objects.commands.SlashArgumentsCompleter;
import java.util.LinkedList;
import java.util.TreeMap;
+@Component
public class SlashCommandCompletionListener extends ListenerAdapter
{
diff --git a/src/main/java/wtf/beatrice/hidekobot/listeners/SlashCommandListener.java b/src/main/java/wtf/beatrice/hidekobot/listeners/SlashCommandListener.java
index bae8d78..d00bf1d 100644
--- a/src/main/java/wtf/beatrice/hidekobot/listeners/SlashCommandListener.java
+++ b/src/main/java/wtf/beatrice/hidekobot/listeners/SlashCommandListener.java
@@ -3,11 +3,13 @@ package wtf.beatrice.hidekobot.listeners;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.objects.commands.SlashCommand;
import java.util.LinkedList;
import java.util.TreeMap;
+@Component
public class SlashCommandListener extends ListenerAdapter
{
diff --git a/src/main/java/wtf/beatrice/hidekobot/repositories/CommandRunnerRepository.java b/src/main/java/wtf/beatrice/hidekobot/repositories/CommandRunnerRepository.java
new file mode 100644
index 0000000..9a28fcd
--- /dev/null
+++ b/src/main/java/wtf/beatrice/hidekobot/repositories/CommandRunnerRepository.java
@@ -0,0 +1,8 @@
+package wtf.beatrice.hidekobot.repositories;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import wtf.beatrice.hidekobot.entities.CommandRunner;
+
+public interface CommandRunnerRepository extends JpaRepository
+{
+}
diff --git a/src/main/java/wtf/beatrice/hidekobot/repositories/PendingDisabledMessageRepository.java b/src/main/java/wtf/beatrice/hidekobot/repositories/PendingDisabledMessageRepository.java
new file mode 100644
index 0000000..c410404
--- /dev/null
+++ b/src/main/java/wtf/beatrice/hidekobot/repositories/PendingDisabledMessageRepository.java
@@ -0,0 +1,8 @@
+package wtf.beatrice.hidekobot.repositories;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import wtf.beatrice.hidekobot.entities.PendingDisabledMessage;
+
+public interface PendingDisabledMessageRepository extends JpaRepository
+{
+}
diff --git a/src/main/java/wtf/beatrice/hidekobot/repositories/UrbanDictionaryRepository.java b/src/main/java/wtf/beatrice/hidekobot/repositories/UrbanDictionaryRepository.java
new file mode 100644
index 0000000..5ab072c
--- /dev/null
+++ b/src/main/java/wtf/beatrice/hidekobot/repositories/UrbanDictionaryRepository.java
@@ -0,0 +1,8 @@
+package wtf.beatrice.hidekobot.repositories;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import wtf.beatrice.hidekobot.entities.UrbanDictionaryEntry;
+
+public interface UrbanDictionaryRepository extends JpaRepository
+{
+}
diff --git a/src/main/java/wtf/beatrice/hidekobot/runnables/ExpiredMessageTask.java b/src/main/java/wtf/beatrice/hidekobot/runnables/ExpiredMessageTask.java
index 2882332..0fd8275 100644
--- a/src/main/java/wtf/beatrice/hidekobot/runnables/ExpiredMessageTask.java
+++ b/src/main/java/wtf/beatrice/hidekobot/runnables/ExpiredMessageTask.java
@@ -3,7 +3,7 @@ package wtf.beatrice.hidekobot.runnables;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import wtf.beatrice.hidekobot.Cache;
-import wtf.beatrice.hidekobot.datasources.DatabaseSource;
+import wtf.beatrice.hidekobot.services.DatabaseService;
import wtf.beatrice.hidekobot.util.CommandUtil;
import java.time.LocalDateTime;
@@ -13,16 +13,20 @@ import java.util.List;
public class ExpiredMessageTask implements Runnable
{
+ private final DatabaseService databaseService;
+ private final CommandUtil commandUtil;
+
private final DateTimeFormatter formatter;
private static final Logger LOGGER = LoggerFactory.getLogger(ExpiredMessageTask.class);
- private DatabaseSource databaseSource;
- public ExpiredMessageTask()
+ public ExpiredMessageTask(DatabaseService databaseService,
+ CommandUtil commandUtil)
{
+ this.databaseService = databaseService;
+ this.commandUtil = commandUtil;
String format = Cache.getExpiryTimestampFormat();
formatter = DateTimeFormatter.ofPattern(format);
- databaseSource = Cache.getDatabaseSource();
}
@@ -30,10 +34,7 @@ public class ExpiredMessageTask implements Runnable
public void run()
{
- databaseSource = Cache.getDatabaseSource();
- if (databaseSource == null) return;
-
- List expiringMessages = Cache.getDatabaseSource().getQueuedExpiringMessages();
+ List expiringMessages = databaseService.getQueuedExpiringMessages();
if (expiringMessages == null || expiringMessages.isEmpty()) return;
LocalDateTime now = LocalDateTime.now();
@@ -43,11 +44,11 @@ public class ExpiredMessageTask implements Runnable
if (Cache.isVerbose()) LOGGER.info("expired check: {}", messageId);
- String expiryTimestamp = databaseSource.getQueuedExpiringMessageExpiryDate(messageId);
+ String expiryTimestamp = databaseService.getQueuedExpiringMessageExpiryDate(messageId);
if (expiryTimestamp == null || expiryTimestamp.isEmpty()) // if missing timestamp
{
// count it as already expired
- databaseSource.untrackExpiredMessage(messageId);
+ databaseService.untrackExpiredMessage(messageId);
// move on to next message
continue;
}
@@ -57,7 +58,7 @@ public class ExpiredMessageTask implements Runnable
if (now.isAfter(expiryDate))
{
if (Cache.isVerbose()) LOGGER.info("expired: {}", messageId);
- CommandUtil.disableExpired(messageId);
+ commandUtil.disableExpired(messageId);
}
}
diff --git a/src/main/java/wtf/beatrice/hidekobot/runnables/TriviaTask.java b/src/main/java/wtf/beatrice/hidekobot/runnables/TriviaTask.java
index 2a0be8a..00d67f6 100644
--- a/src/main/java/wtf/beatrice/hidekobot/runnables/TriviaTask.java
+++ b/src/main/java/wtf/beatrice/hidekobot/runnables/TriviaTask.java
@@ -13,6 +13,7 @@ import wtf.beatrice.hidekobot.objects.comparators.TriviaScoreComparator;
import wtf.beatrice.hidekobot.objects.fun.TriviaCategory;
import wtf.beatrice.hidekobot.objects.fun.TriviaQuestion;
import wtf.beatrice.hidekobot.objects.fun.TriviaScore;
+import wtf.beatrice.hidekobot.services.DatabaseService;
import wtf.beatrice.hidekobot.util.CommandUtil;
import java.util.*;
@@ -20,6 +21,10 @@ import java.util.concurrent.ScheduledFuture;
public class TriviaTask implements Runnable
{
+
+ private final DatabaseService databaseService;
+ private final CommandUtil commandUtil;
+
private final User author;
private final MessageChannel channel;
@@ -33,11 +38,17 @@ public class TriviaTask implements Runnable
private int iteration = 0;
- public TriviaTask(User author, MessageChannel channel, TriviaCategory category)
+ public TriviaTask(User author,
+ MessageChannel channel,
+ TriviaCategory category,
+ DatabaseService databaseService,
+ CommandUtil commandUtil)
{
this.author = author;
this.channel = channel;
this.category = category;
+ this.databaseService = databaseService;
+ this.commandUtil = commandUtil;
triviaJson = Trivia.fetchJson(Trivia.getTriviaLink(category.categoryId()));
questions = Trivia.parseQuestions(triviaJson); //todo: null check, rate limiting...
@@ -55,7 +66,7 @@ public class TriviaTask implements Runnable
if (previousMessage != null)
{
// todo: we shouldn't use this method, since it messes with the database... look at coin reflip
- CommandUtil.disableExpired(previousMessage.getId());
+ commandUtil.disableExpired(previousMessage.getId());
String previousCorrectAnswer = questions.get(iteration - 1).correctAnswer();
@@ -193,12 +204,12 @@ public class TriviaTask implements Runnable
.complete();
- Cache.getDatabaseSource().trackRanCommandReply(previousMessage, author);
+ databaseService.trackRanCommandReply(previousMessage, author);
// todo: ^ we should get rid of this tracking, since we don't need to know who started the trivia.
// todo: however, for now, that's the only way to avoid a thread-locking scenario as some data is
// todo: only stored in that table. this should be solved when we merge / fix the two main tables.
// todo: then, we can remove this instruction.
- Cache.getDatabaseSource().queueDisabling(previousMessage);
+ databaseService.queueDisabling(previousMessage);
iteration++;
}
diff --git a/src/main/java/wtf/beatrice/hidekobot/services/DatabaseService.java b/src/main/java/wtf/beatrice/hidekobot/services/DatabaseService.java
new file mode 100644
index 0000000..8517ad6
--- /dev/null
+++ b/src/main/java/wtf/beatrice/hidekobot/services/DatabaseService.java
@@ -0,0 +1,183 @@
+package wtf.beatrice.hidekobot.services;
+
+import net.dv8tion.jda.api.entities.Message;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.channel.ChannelType;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import wtf.beatrice.hidekobot.Cache;
+import wtf.beatrice.hidekobot.entities.CommandRunner;
+import wtf.beatrice.hidekobot.entities.PendingDisabledMessage;
+import wtf.beatrice.hidekobot.entities.UrbanDictionaryEntry;
+import wtf.beatrice.hidekobot.repositories.CommandRunnerRepository;
+import wtf.beatrice.hidekobot.repositories.PendingDisabledMessageRepository;
+import wtf.beatrice.hidekobot.repositories.UrbanDictionaryRepository;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+@Service
+@Transactional
+public class DatabaseService
+{
+
+ private final PendingDisabledMessageRepository pendingRepo;
+ private final CommandRunnerRepository runnerRepo;
+ private final UrbanDictionaryRepository urbanRepo;
+
+ public DatabaseService(PendingDisabledMessageRepository p, CommandRunnerRepository c, UrbanDictionaryRepository u)
+ {
+ this.pendingRepo = p;
+ this.runnerRepo = c;
+ this.urbanRepo = u;
+ }
+
+ // trackRanCommandReply
+ public void trackRanCommandReply(Message message, User user)
+ {
+ String userId = user.getId();
+ String guildId = message.getChannelType().isGuild() ? message.getGuild().getId() : userId;
+
+ CommandRunner row = new CommandRunner();
+ row.setMessageId(message.getId());
+ row.setGuildId(guildId);
+ row.setChannelId(message.getChannel().getId());
+ row.setUserId(userId);
+ row.setChannelType(message.getChannelType().name());
+
+ runnerRepo.save(row);
+ }
+
+ public boolean isUserTrackedFor(String userId, String messageId)
+ {
+ return runnerRepo.findById(messageId)
+ .map(r -> userId.equals(r.getUserId()))
+ .orElse(false);
+ }
+
+
+ public ChannelType getTrackedMessageChannelType(String messageId)
+ {
+ return runnerRepo.findById(messageId)
+ .map(r -> ChannelType.valueOf(r.getChannelType()))
+ .orElse(null);
+ }
+
+ public String getTrackedReplyUserId(String messageId)
+ {
+ return runnerRepo.findById(messageId)
+ .map(CommandRunner::getUserId)
+ .orElse(null);
+ }
+
+ public void queueDisabling(Message message)
+ {
+ String guildId = message.getChannelType().isGuild() ? message.getGuild().getId() : "PRIVATE";
+
+ LocalDateTime expiry = LocalDateTime.now().plusSeconds(Cache.getExpiryTimeSeconds());
+ String formatted = DateTimeFormatter.ofPattern(Cache.getExpiryTimestampFormat()).format(expiry);
+
+ PendingDisabledMessage row = new PendingDisabledMessage();
+ row.setMessageId(message.getId());
+ row.setChannelId(message.getChannel().getId());
+ row.setGuildId(guildId);
+ row.setExpiryTimestamp(formatted);
+
+ pendingRepo.save(row);
+ }
+
+ public List getQueuedExpiringMessages()
+ {
+ return pendingRepo.findAll()
+ .stream()
+ .map(PendingDisabledMessage::getMessageId)
+ .toList();
+ }
+
+ public void untrackExpiredMessage(String messageId)
+ {
+ pendingRepo.deleteById(messageId);
+ runnerRepo.deleteById(messageId);
+ urbanRepo.deleteById(messageId);
+ }
+
+ public String getQueuedExpiringMessageExpiryDate(String messageId)
+ {
+ return pendingRepo.findById(messageId).map(PendingDisabledMessage::getExpiryTimestamp).orElse(null);
+ }
+
+ public String getQueuedExpiringMessageChannel(String messageId)
+ {
+ return pendingRepo.findById(messageId).map(PendingDisabledMessage::getChannelId).orElse(null);
+ }
+
+ public String getQueuedExpiringMessageGuild(String messageId)
+ {
+ return pendingRepo.findById(messageId).map(PendingDisabledMessage::getGuildId).orElse(null);
+ }
+
+ public void trackUrban(String meanings, String examples, String contributors, String dates, Message message, String term)
+ {
+ UrbanDictionaryEntry e = new UrbanDictionaryEntry();
+ e.setMessageId(message.getId());
+ e.setPage(0);
+ e.setMeanings(meanings);
+ e.setExamples(examples);
+ e.setContributors(contributors);
+ e.setDates(dates);
+ e.setTerm(term);
+ urbanRepo.save(e);
+ }
+
+ public int getUrbanPage(String messageId)
+ {
+ return urbanRepo.findById(messageId)
+ .map(UrbanDictionaryEntry::getPage)
+ .orElse(0);
+ }
+
+ public String getUrbanMeanings(String messageId)
+ {
+ return urbanRepo.findById(messageId).map(UrbanDictionaryEntry::getMeanings).orElse(null);
+ }
+
+ public String getUrbanExamples(String messageId)
+ {
+ return urbanRepo.findById(messageId).map(UrbanDictionaryEntry::getExamples).orElse(null);
+ }
+
+ public String getUrbanContributors(String messageId)
+ {
+ return urbanRepo.findById(messageId).map(UrbanDictionaryEntry::getContributors).orElse(null);
+ }
+
+ public String getUrbanDates(String messageId)
+ {
+ return urbanRepo.findById(messageId).map(UrbanDictionaryEntry::getDates).orElse(null);
+ }
+
+ public String getUrbanTerm(String messageId)
+ {
+ return urbanRepo.findById(messageId).map(UrbanDictionaryEntry::getTerm).orElse(null);
+ }
+
+ public void setUrbanPage(String messageId, int page)
+ {
+ urbanRepo.findById(messageId).ifPresent(e -> {
+ e.setPage(page);
+ urbanRepo.save(e);
+ });
+ }
+
+ public void resetExpiryTimestamp(String messageId)
+ {
+ pendingRepo.findById(messageId).ifPresent(row -> {
+ String formatted = DateTimeFormatter
+ .ofPattern(Cache.getExpiryTimestampFormat())
+ .format(LocalDateTime.now().plusSeconds(Cache.getExpiryTimeSeconds()));
+ row.setExpiryTimestamp(formatted);
+ pendingRepo.save(row);
+ });
+ }
+}
diff --git a/src/main/java/wtf/beatrice/hidekobot/util/CommandUtil.java b/src/main/java/wtf/beatrice/hidekobot/util/CommandUtil.java
index bb321f2..9cd66f3 100644
--- a/src/main/java/wtf/beatrice/hidekobot/util/CommandUtil.java
+++ b/src/main/java/wtf/beatrice/hidekobot/util/CommandUtil.java
@@ -14,22 +14,27 @@ import net.dv8tion.jda.api.interactions.components.LayoutComponent;
import net.dv8tion.jda.api.requests.RestAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.HidekoBot;
-import wtf.beatrice.hidekobot.datasources.DatabaseSource;
import wtf.beatrice.hidekobot.objects.commands.SlashCommand;
+import wtf.beatrice.hidekobot.services.DatabaseService;
import java.util.ArrayList;
import java.util.List;
+@Component
public class CommandUtil
{
private static final Logger LOGGER = LoggerFactory.getLogger(CommandUtil.class);
- private CommandUtil()
+ private final DatabaseService databaseService;
+
+ public CommandUtil(@Autowired DatabaseService databaseService)
{
- throw new IllegalStateException("Utility class");
+ this.databaseService = databaseService;
}
/**
@@ -38,10 +43,10 @@ public class CommandUtil
*
* @param event the button interaction event.
*/
- public static void delete(ButtonInteractionEvent event)
+ public void delete(ButtonInteractionEvent event)
{
// check if the user interacting is the same one who ran the command
- if (!(Cache.getDatabaseSource().isUserTrackedFor(event.getUser().getId(), event.getMessageId())))
+ if (!databaseService.isUserTrackedFor(event.getUser().getId(), event.getMessageId()))
{
event.reply("❌ You did not run this command!").setEphemeral(true).queue();
return;
@@ -60,7 +65,7 @@ public class CommandUtil
*
* @param force a boolean specifying if the update should be forced even if no differences were found.
*/
- public static void updateSlashCommands(boolean force)
+ public void updateSlashCommands(boolean force)
{
// populate commands list from registered commands
@@ -160,48 +165,46 @@ public class CommandUtil
*
* @param messageId the message id to disable.
*/
- public static void disableExpired(String messageId)
+ public void disableExpired(String messageId)
{
- DatabaseSource databaseSource = Cache.getDatabaseSource();
-
- String channelId = databaseSource.getQueuedExpiringMessageChannel(messageId);
+ String channelId = databaseService.getQueuedExpiringMessageChannel(messageId);
// todo: warning, the following method + related if check are thread-locking.
// todo: we should probably merge the two tables somehow, since they have redundant information.
- ChannelType msgChannelType = databaseSource.getTrackedMessageChannelType(messageId);
+ ChannelType msgChannelType = databaseService.getTrackedMessageChannelType(messageId);
MessageChannel textChannel = null;
// this should never happen, but only message channels are supported.
if (!msgChannelType.isMessage())
{
- databaseSource.untrackExpiredMessage(messageId);
+ databaseService.untrackExpiredMessage(messageId);
return;
}
// if this is a DM
if (!(msgChannelType.isGuild()))
{
- String userId = databaseSource.getTrackedReplyUserId(messageId);
+ String userId = databaseService.getTrackedReplyUserId(messageId);
User user = userId == null ? null : HidekoBot.getAPI().retrieveUserById(userId).complete();
if (user == null)
{
// if user is not found, consider it expired
// (deleted profile, or blocked the bot)
- databaseSource.untrackExpiredMessage(messageId);
+ databaseService.untrackExpiredMessage(messageId);
return;
}
textChannel = user.openPrivateChannel().complete();
} else
{
- String guildId = databaseSource.getQueuedExpiringMessageGuild(messageId);
+ String guildId = databaseService.getQueuedExpiringMessageGuild(messageId);
Guild guild = guildId == null ? null : HidekoBot.getAPI().getGuildById(guildId);
if (guild == null)
{
// if guild is not found, consider it expired
// (server was deleted or bot was kicked)
- databaseSource.untrackExpiredMessage(messageId);
+ databaseService.untrackExpiredMessage(messageId);
return;
}
textChannel = guild.getTextChannelById(channelId);
@@ -211,7 +214,7 @@ public class CommandUtil
{
// if channel is not found, count it as expired
// (channel was deleted or bot permissions restricted)
- databaseSource.untrackExpiredMessage(messageId);
+ databaseService.untrackExpiredMessage(messageId);
return;
}
@@ -224,7 +227,7 @@ public class CommandUtil
message -> {
if (message == null)
{
- databaseSource.untrackExpiredMessage(messageId);
+ databaseService.untrackExpiredMessage(messageId);
return;
}
@@ -237,9 +240,9 @@ public class CommandUtil
}
message.editMessageComponents(newComponents).queue();
- databaseSource.untrackExpiredMessage(messageId);
+ databaseService.untrackExpiredMessage(messageId);
},
- error -> databaseSource.untrackExpiredMessage(messageId));
+ error -> databaseService.untrackExpiredMessage(messageId));
}
}
diff --git a/src/main/java/wtf/beatrice/hidekobot/util/Services.java b/src/main/java/wtf/beatrice/hidekobot/util/Services.java
new file mode 100644
index 0000000..d5cd0f7
--- /dev/null
+++ b/src/main/java/wtf/beatrice/hidekobot/util/Services.java
@@ -0,0 +1,7 @@
+package wtf.beatrice.hidekobot.util;
+
+import wtf.beatrice.hidekobot.services.DatabaseService;
+
+public record Services(CommandUtil commandUtil, DatabaseService databaseService)
+{
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..d8ca95b
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,8 @@
+spring.datasource.url=jdbc:sqlite:/absolute/path/to/hidekobot.db
+spring.datasource.driver-class-name=org.sqlite.JDBC
+# let Hibernate create/update tables for you during the migration
+spring.jpa.hibernate.ddl-auto=update
+spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
+# optional logging while migrating
+spring.jpa.show-sql=true
+spring.jpa.properties.hibernate.format_sql=true