Implement SQLite database solving #1
All checks were successful
continuous-integration/drone/push Build is passing

A new basic database has been laid out, with support for message expiry and disabling buttons for old messages.
This commit is contained in:
Bea 2022-11-21 00:14:13 +01:00
parent 7ffd3442c2
commit 98a162a33b
7 changed files with 569 additions and 115 deletions

BIN
db.sqlite Normal file

Binary file not shown.

View File

@ -30,6 +30,12 @@
<artifactId>slf4j-simple</artifactId> <artifactId>slf4j-simple</artifactId>
<version>2.0.0</version> <version>2.0.0</version>
</dependency> </dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.39.4.1</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -1,17 +1,23 @@
package wtf.beatrice.hidekobot; package wtf.beatrice.hidekobot;
import org.jetbrains.annotations.Nullable;
import wtf.beatrice.hidekobot.database.DatabaseManager;
import wtf.beatrice.hidekobot.listeners.MessageLogger; import wtf.beatrice.hidekobot.listeners.MessageLogger;
public class Configuration public class Configuration
{ {
private static DatabaseManager dbManager = null;
private static boolean verbose = false; private static boolean verbose = false;
private static MessageLogger verbosityLogger; private static MessageLogger verbosityLogger;
// todo: allow people to set their own user id // todo: allow people to set their own user id
private static final long botOwnerId = 979809420714332260L; private static final long botOwnerId = 979809420714332260L;
private final static String expiryTimestampFormat = "yy/MM/dd HH:mm:ss";
private final static long expiryTimeSeconds = 60L;
private final static String defaultInviteLink = private final static String defaultInviteLink =
"https://discord.com/api/oauth2/authorize?client_id=%userid%&scope=bot+applications.commands&permissions=8"; "https://discord.com/api/oauth2/authorize?client_id=%userid%&scope=bot+applications.commands&permissions=8";
@ -95,4 +101,35 @@ public class Configuration
return defaultInviteLink.replace("%userid%", botApplicationId); return defaultInviteLink.replace("%userid%", botApplicationId);
} }
/**
* Set the already fully-initialized DatabaseManager instance, ready to be accessed and used.
*
* @param databaseManagerInstance the fully-initialized DatabaseManager instance.
*/
public static void setDatabaseManagerInstance(DatabaseManager databaseManagerInstance)
{
dbManager = databaseManagerInstance;
}
/**
* Get the fully-initialized DatabaseManager instance, ready to be used.
*
* @return the DatabaseManager instance.
*/
public static @Nullable DatabaseManager getDatabaseManager() { return dbManager; }
/**
* Get the DateTimeFormatter string for parsing the expired messages timestamp.
*
* @return the String of the DateTimeFormatter format.
*/
public static String getExpiryTimestampFormat(){ return expiryTimestampFormat; }
/**
* Get the amount of seconds after which a message expires.
*
* @return long value of the expiry seconds.
*/
public static long getExpiryTimeSeconds() { return expiryTimeSeconds; }
} }

View File

@ -6,17 +6,21 @@ import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.requests.GatewayIntent;
import sun.misc.Signal; import sun.misc.Signal;
import wtf.beatrice.hidekobot.database.DatabaseManager;
import wtf.beatrice.hidekobot.listeners.ButtonInteractionListener; import wtf.beatrice.hidekobot.listeners.ButtonInteractionListener;
import wtf.beatrice.hidekobot.listeners.MessageListener; import wtf.beatrice.hidekobot.listeners.MessageListener;
import wtf.beatrice.hidekobot.listeners.SlashCommandCompleter; import wtf.beatrice.hidekobot.listeners.SlashCommandCompleter;
import wtf.beatrice.hidekobot.listeners.SlashCommandListener; import wtf.beatrice.hidekobot.listeners.SlashCommandListener;
import wtf.beatrice.hidekobot.utils.ExpiredMessageRunner;
import wtf.beatrice.hidekobot.utils.Logger; import wtf.beatrice.hidekobot.utils.Logger;
import wtf.beatrice.hidekobot.utils.SlashCommandsUtil; import wtf.beatrice.hidekobot.utils.SlashCommandsUtil;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class HidekoBot public class HidekoBot
@ -93,6 +97,30 @@ public class HidekoBot
jda.getPresence().setStatus(OnlineStatus.ONLINE); jda.getPresence().setStatus(OnlineStatus.ONLINE);
jda.getPresence().setActivity(Activity.playing("Hatsune Miku: Project DIVA")); jda.getPresence().setActivity(Activity.playing("Hatsune Miku: Project DIVA"));
// connect to database
logger.log("Connecting to database...");
String dbFilePath = System.getProperty("user.dir") + File.separator + "db.sqlite"; // in current directory
DatabaseManager dbManager = new DatabaseManager(dbFilePath);
if(dbManager.connect() && dbManager.initDb())
{
logger.log("Database connection initialized!");
Configuration.setDatabaseManagerInstance(dbManager);
// load data here...
logger.log("Database data loaded into memory!");
} else {
logger.log("Error initializing database connection!");
}
// start scheduled runnables
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
ExpiredMessageRunner task = new ExpiredMessageRunner();
int initDelay = 5;
int periodicDelay = 5;
scheduler.scheduleAtFixedRate(task, initDelay, periodicDelay, TimeUnit.SECONDS);
// print the bot logo. // print the bot logo.
logger.log("\n\n" + logger.getLogo() + "\nv" + version + " - bot is ready!\n", 2); logger.log("\n\n" + logger.getLogo() + "\nv" + version + " - bot is ready!\n", 2);

View File

@ -10,7 +10,9 @@ import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionHook; import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.restaction.WebhookMessageEditAction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import wtf.beatrice.hidekobot.Configuration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -20,145 +22,161 @@ public class ClearChatCommand
public void runSlashCommand(@NotNull SlashCommandInteractionEvent event) public void runSlashCommand(@NotNull SlashCommandInteractionEvent event)
{ {
MessageChannel channel = event.getChannel();
if(!(channel instanceof TextChannel)) // run in a new thread, so we don't block the main one
new Thread(() ->
{ {
event.reply("Sorry! I can't delete messages here.").queue();
return;
}
/* get the amount from the command args. MessageChannel channel = event.getChannel();
NULL should not be possible because we specified them as mandatory,
but apparently the mobile app doesn't care and still sends the command if you omit the args. */
OptionMapping amountMapping = event.getOption("amount");
int toDeleteAmount = amountMapping == null ? 1 : amountMapping.getAsInt();
if(toDeleteAmount <= 0) if(!(channel instanceof TextChannel))
{
event.reply("Sorry, I can't delete that amount of messages!").queue();
}
else {
// answer by saying that the operation has begun.
InteractionHook replyInteraction = event.reply("\uD83D\uDEA7 Clearing...").complete();
// int to keep track of how many messages we actually deleted.
int deleted = 0;
int limit = 95; //discord limits this method to range 2-100. we set it to 95 to be safe.
// increase the count by 1, because we technically aren't clearing the first ID ever
// which is actually the slash command's ID and not a message.
toDeleteAmount++;
// count how many times we have to iterate this to delete the full <toDeleteAmount> messages.
int iterations = toDeleteAmount / limit;
//if there are some messages left, but less than <limit>, we need one more iterations.
int remainder = toDeleteAmount % limit;
if(remainder != 0) iterations++;
// set the starting point.
long messageId = event.getInteraction().getIdLong();
// boolean to see if we're trying to delete more messages than possible.
boolean outOfBounds = false;
// do iterate.
for(int iteration = 0; iteration < iterations; iteration++)
{ {
if(outOfBounds) break; event.reply("Sorry! I can't delete messages here.").queue();
return;
}
// set how many messages to delete for this iteration (usually <limit> unless there's a remainder) /* get the amount from the command args.
int iterationSize = limit; NULL should not be possible because we specified them as mandatory,
but apparently the mobile app doesn't care and still sends the command if you omit the args. */
OptionMapping amountMapping = event.getOption("amount");
int toDeleteAmount = amountMapping == null ? 1 : amountMapping.getAsInt();
// if we are at the last iteration... if(toDeleteAmount <= 0)
if(iteration+1 == iterations) {
event.reply("Sorry, I can't delete that amount of messages!").queue();
}
else {
// answer by saying that the operation has begun.
InteractionHook replyInteraction = event.reply("\uD83D\uDEA7 Clearing...").complete();
// int to keep track of how many messages we actually deleted.
int deleted = 0;
int limit = 95; //discord limits this method to range 2-100. we set it to 95 to be safe.
// increase the count by 1, because we technically aren't clearing the first ID ever
// which is actually the slash command's ID and not a message.
toDeleteAmount++;
// count how many times we have to iterate this to delete the full <toDeleteAmount> messages.
int iterations = toDeleteAmount / limit;
//if there are some messages left, but less than <limit>, we need one more iterations.
int remainder = toDeleteAmount % limit;
if(remainder != 0) iterations++;
// set the starting point.
long messageId = event.getInteraction().getIdLong();
// boolean to see if we're trying to delete more messages than possible.
boolean outOfBounds = false;
// do iterate.
for(int iteration = 0; iteration < iterations; iteration++)
{ {
// check if we have <limit> or fewer messages to delete if(outOfBounds) break;
if(remainder != 0) iterationSize = remainder;
}
if(iterationSize == 1) // set how many messages to delete for this iteration (usually <limit> unless there's a remainder)
{ int iterationSize = limit;
// grab the message
Message toDelete = ((TextChannel)channel).retrieveMessageById(messageId).complete();
//only delete one message
if(toDelete != null) toDelete.delete().queue();
else outOfBounds = true;
// increase deleted counter by 1
deleted++;
} else {
// get the last <iterationSize - 1> messages.
MessageHistory.MessageRetrieveAction action = channel.getHistoryBefore(messageId, iterationSize - 1);
// note: first one is the most recent, last one is the oldest message.
List<Message> messages = new ArrayList<>();
// (we are skipping first iteration since it would return an error, given that the id is the slash command and not a message)
if(iteration!=0) messages.add(((TextChannel)channel).retrieveMessageById(messageId).complete());
messages.addAll(action.complete().getRetrievedHistory());
// check if we only have one or zero messages left (trying to delete more than possible) // if we are at the last iteration...
if(messages.size() <= 1) if(iteration+1 == iterations)
{ {
outOfBounds = true; // check if we have <limit> or fewer messages to delete
} else { if(remainder != 0) iterationSize = remainder;
// before deleting, we need to grab the <previous to the oldest> message's id for next iteration. }
action = channel.getHistoryBefore(messages.get(messages.size() - 1).getIdLong(), 1);
List<Message> previousMessage = action.complete().getRetrievedHistory(); if(iterationSize == 1)
{
// if that message exists (we are not out of bounds)... store it // grab the message
if(!previousMessage.isEmpty()) messageId = previousMessage.get(0).getIdLong(); Message toDelete = ((TextChannel)channel).retrieveMessageById(messageId).complete();
//only delete one message
if(toDelete != null) toDelete.delete().queue();
else outOfBounds = true; else outOfBounds = true;
} // increase deleted counter by 1
deleted++;
} else {
// get the last <iterationSize - 1> messages.
MessageHistory.MessageRetrieveAction action = channel.getHistoryBefore(messageId, iterationSize - 1);
// note: first one is the most recent, last one is the oldest message.
List<Message> messages = new ArrayList<>();
// (we are skipping first iteration since it would return an error, given that the id is the slash command and not a message)
if(iteration!=0) messages.add(((TextChannel)channel).retrieveMessageById(messageId).complete());
messages.addAll(action.complete().getRetrievedHistory());
// queue messages for deletion // check if we only have one or zero messages left (trying to delete more than possible)
if(messages.size() == 1) if(messages.size() <= 1)
{
messages.get(0).delete().queue();
}
else if(!messages.isEmpty())
{
try {
((TextChannel) channel).deleteMessages(messages).complete();
/* alternatively, we could use purgeMessages, which is smarter...
however, it also tries to delete messages older than 2 weeks
which are restricted by discord, and thus has to use
a less efficient way that triggers rate-limiting very quickly. */
} catch (Exception e)
{ {
replyInteraction.editOriginal("\uD83D\uDE22 Sorry, it seems like there was an issue! " + e.getMessage()).queue(); outOfBounds = true;
return; // warning: this quits everything. } else {
// before deleting, we need to grab the <previous to the oldest> message's id for next iteration.
action = channel.getHistoryBefore(messages.get(messages.size() - 1).getIdLong(), 1);
List<Message> previousMessage = action.complete().getRetrievedHistory();
// if that message exists (we are not out of bounds)... store it
if(!previousMessage.isEmpty()) messageId = previousMessage.get(0).getIdLong();
else outOfBounds = true;
} }
// queue messages for deletion
if(messages.size() == 1)
{
messages.get(0).delete().queue();
}
else if(!messages.isEmpty())
{
try {
((TextChannel) channel).deleteMessages(messages).complete();
/* alternatively, we could use purgeMessages, which is smarter...
however, it also tries to delete messages older than 2 weeks
which are restricted by discord, and thus has to use
a less efficient way that triggers rate-limiting very quickly. */
} catch (Exception e)
{
replyInteraction.editOriginal("\uD83D\uDE22 Sorry, it seems like there was an issue! " + e.getMessage()).queue();
return; // warning: this quits everything.
}
}
// increase deleted counter by <list size>
deleted += messages.size();
} }
// increase deleted counter by <list size>
deleted += messages.size();
} }
Button deleteButton = Button.danger("clear_delete", "Delete").withEmoji(Emoji.fromUnicode(""));
WebhookMessageEditAction<Message> webhookMessageEditAction;
// log having deleted the messages (or not).
if(deleted < 1)
{
webhookMessageEditAction = replyInteraction.editOriginal("\uD83D\uDE22 Couldn't clear any message!");
} else if(deleted == 1)
{
webhookMessageEditAction = replyInteraction.editOriginal("✂ Cleared 1 message!");
} else {
webhookMessageEditAction = replyInteraction.editOriginal("✂ Cleared " + deleted + " messages!");
}
Message message = webhookMessageEditAction
.setActionRow(deleteButton)
.complete();
String replyMessageId = message.getId();
String replyChannelId = message.getChannel().getId();
String replyGuildId = message.getGuild().getId();
Configuration.getDatabaseManager().queueDisabling(replyGuildId, replyChannelId, replyMessageId);
} }
}).start();
Button deleteButton = Button.danger("clear_delete", "Delete").withEmoji(Emoji.fromUnicode(""));
// log having deleted the messages (or not).
if(deleted < 1)
{
replyInteraction.editOriginal("\uD83D\uDE22 Couldn't clear any message!")
.setActionRow(deleteButton).queue();
} else if(deleted == 1)
{
replyInteraction.editOriginal("✂ Cleared 1 message!")
.setActionRow(deleteButton).queue();
} else {
replyInteraction.editOriginal("✂ Cleared " + deleted + " messages!")
.setActionRow(deleteButton).queue();
}
}
} }
public void deleteButton(ButtonInteractionEvent event) public void deleteButton(ButtonInteractionEvent event)
{ {
// todo: permissions check
event.getInteraction().getMessage().delete().queue(); event.getInteraction().getMessage().delete().queue();
} }
} }

View File

@ -0,0 +1,266 @@
package wtf.beatrice.hidekobot.database;
import wtf.beatrice.hidekobot.Configuration;
import wtf.beatrice.hidekobot.utils.Logger;
import java.sql.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
public class DatabaseManager
{
private final static String sqliteURL = "jdbc:sqlite:%path%";
private Connection dbConnection = null;
private final String dbPath;
private final Logger logger;
public DatabaseManager(String dbPath)
{
this.dbPath = dbPath;
this.logger = new Logger(getClass());
}
public boolean connect()
{
String url = sqliteURL.replace("%path%", dbPath);
if(!close()) return false;
try {
dbConnection = DriverManager.getConnection(url);
logger.log("Database connection established!");
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public boolean close()
{
if (dbConnection != null)
{
try {
if(!dbConnection.isClosed())
{
dbConnection.close();
}
} catch (SQLException e) {
e.printStackTrace();
return false;
}
dbConnection = null;
}
return true;
}
public boolean initDb()
{
List<String> 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," + // channel the command was run in
"message_id TEXT NOT NULL," + // message id of the bot's response
"user_id TEXT NOT NULL" + // user who ran the command
");");
for(String sql : newTables)
{
try (Statement stmt = dbConnection.createStatement()) {
// execute the statement
stmt.execute(sql);
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
return true;
}
public boolean queueDisabling(String guildId, String channelId, String messageId)
{
LocalDateTime expiryTime = LocalDateTime.now().plusSeconds(Configuration.getExpiryTimeSeconds());
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(Configuration.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)
{
e.printStackTrace();
}
return false;
}
public List<String> getQueuedExpiringMessages()
{
List<String> 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) {
e.printStackTrace();
}
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)
{
e.printStackTrace();
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)
{
e.printStackTrace();
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) {
e.printStackTrace();
}
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) {
e.printStackTrace();
}
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) {
e.printStackTrace();
}
return null;
}
/**
* 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 |
* --------------------------------------------------------------------------
* | 39402849302 | 39402849302 | 39402849302 | 39402849302 |
* --------------------------------------------------------------------------
*
*/
}

View File

@ -0,0 +1,99 @@
package wtf.beatrice.hidekobot.utils;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.interactions.components.LayoutComponent;
import net.dv8tion.jda.api.requests.RestAction;
import wtf.beatrice.hidekobot.Configuration;
import wtf.beatrice.hidekobot.HidekoBot;
import wtf.beatrice.hidekobot.database.DatabaseManager;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
public class ExpiredMessageRunner implements Runnable {
private final DateTimeFormatter formatter;
private final Logger logger;
private DatabaseManager databaseManager;
public ExpiredMessageRunner()
{
String format = Configuration.getExpiryTimestampFormat();
formatter = DateTimeFormatter.ofPattern(format);
databaseManager = Configuration.getDatabaseManager();
logger = new Logger(getClass());
}
@Override
public void run() {
databaseManager = Configuration.getDatabaseManager();
if(databaseManager == null) return;
List<String> expiringMessages = Configuration.getDatabaseManager().getQueuedExpiringMessages();
if(expiringMessages == null || expiringMessages.isEmpty()) return;
LocalDateTime now = LocalDateTime.now();
for(String messageId : expiringMessages)
{
logger.log("ID: " + messageId);
String expiryTimestamp = databaseManager.getQueuedExpiringMessageExpiryDate(messageId);
if(expiryTimestamp == null || expiryTimestamp.equals("")) continue; //todo: idk count it as expired already?
LocalDateTime expiryDate = LocalDateTime.parse(expiryTimestamp, formatter);
if(now.isAfter(expiryDate))
{
disableExpired(messageId);
}
}
}
private void disableExpired(String messageId)
{
String guildId = databaseManager.getQueuedExpiringMessageGuild(messageId);
String channelId = databaseManager.getQueuedExpiringMessageChannel(messageId);
Guild guild = HidekoBot.getAPI().getGuildById(guildId);
if(guild == null) return; //todo count it as done/solved/removed? we probably got kicked
TextChannel textChannel = guild.getTextChannelById(channelId);
if(textChannel == null) return; //todo count it as done/solved/removed? channel was probably deleted
RestAction<Message> retrieveAction = textChannel.retrieveMessageById(messageId);
retrieveAction.queue(
message -> {
if(message == null) return; //todo count it as done/solved/removed? message was probably deleted
List<LayoutComponent> components = message.getComponents();
List<LayoutComponent> newComponents = new ArrayList<>();
for (LayoutComponent component : components)
{
component = component.asDisabled();
newComponents.add(component);
}
message.editMessageComponents(newComponents).queue();
databaseManager.untrackExpiredMessage(messageId);
},
(error) -> {
databaseManager.untrackExpiredMessage(messageId);
});
}
}