18 Commits

Author SHA1 Message Date
8e17e55341 move to 0.9.3-snapshot
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
2025-09-06 22:14:58 +02:00
1f2bafa7f8 (wip) migrate commands to components
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-06 22:14:44 +02:00
eafa80f1d2 rename command classes
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-06 21:47:23 +02:00
5ad1d9e891 start moving to @Components
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-06 21:44:55 +02:00
dcc4785edc edit text
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-06 17:59:28 +02:00
a1192db62b fix timeout duration check
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-05 13:15:39 +02:00
910b7a406c show lowercase version
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-05 13:11:43 +02:00
eb953390e3 fix ver
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
2025-09-05 13:07:22 +02:00
5d8fc55276 move to 0.9.2-snapshot
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
2025-09-05 13:03:15 +02:00
784ce11d6b remove old #0000 discriminator
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-05 13:02:59 +02:00
799891ad6b move to v0.9.1-snapshot
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-05 12:50:00 +02:00
0c575378f3 fix concurrency and ack
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-05 12:49:37 +02:00
5015e82700 fix build jar
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
2025-09-05 01:53:05 +02:00
29f486566b move util to service
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing
2025-09-05 01:35:15 +02:00
f80a49995b (wip) migrate to spring beans
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-05 01:32:46 +02:00
bbd0299103 Merge branch 'main' into develop
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-05 00:06:44 +02:00
bb674240bb (wip) switch to spring/hibernate
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-05 00:05:51 +02:00
5a34e5994e add spring/hibernate deps
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-04 23:42:48 +02:00
73 changed files with 1275 additions and 1219 deletions

82
pom.xml
View File

@@ -6,14 +6,16 @@
<groupId>wtf.beatrice.hidekobot</groupId> <groupId>wtf.beatrice.hidekobot</groupId>
<artifactId>HidekoBot</artifactId> <artifactId>HidekoBot</artifactId>
<version>0.6.3-SNAPSHOT</version> <version>0.9.3-SNAPSHOT</version>
<properties> <properties>
<maven.compiler.source>21</maven.compiler.source> <maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sonar.dependencyCheck.htmlReportPath>./target/dependency-check-report.html</sonar.dependencyCheck.htmlReportPath> <sonar.dependencyCheck.htmlReportPath>./target/dependency-check-report.html
<sonar.dependencyCheck.jsonReportPath>./target/dependency-check-report.json</sonar.dependencyCheck.jsonReportPath> </sonar.dependencyCheck.htmlReportPath>
<sonar.dependencyCheck.jsonReportPath>./target/dependency-check-report.json
</sonar.dependencyCheck.jsonReportPath>
<sonar.dependencyCheck.summarize>true</sonar.dependencyCheck.summarize> <sonar.dependencyCheck.summarize>true</sonar.dependencyCheck.summarize>
</properties> </properties>
@@ -30,11 +32,6 @@
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
<version>2.0.17</version> <version>2.0.17</version>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.17</version>
</dependency>
<!-- Dependency used for SQLite database connections--> <!-- Dependency used for SQLite database connections-->
<dependency> <dependency>
@@ -94,6 +91,31 @@
<version>5.13.0</version> <version>5.13.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.4.5</version>
</dependency>
<!-- Hibernate core + SQLite dialects -->
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.6.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-community-dialects</artifactId>
<version>6.6.1.Final</version>
</dependency>
<!-- Jakarta Persistence API (usually provided via Hibernate, but include explicitly for compile-time types) -->
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies> </dependencies>
<!-- override dependencies to use newer versions --> <!-- override dependencies to use newer versions -->
@@ -117,29 +139,6 @@
</resources> </resources>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>wtf.beatrice.hidekobot.HidekoBot</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
@@ -160,7 +159,9 @@
<failBuildOnCVSS>8</failBuildOnCVSS> <failBuildOnCVSS>8</failBuildOnCVSS>
<!--suppress UnresolvedMavenProperty --> <!--suppress UnresolvedMavenProperty -->
<nvdApiKey>${nvdApiKey}</nvdApiKey> <nvdApiKey>${nvdApiKey}</nvdApiKey>
<knownExploitedUrl>https://raw.githubusercontent.com/EugenMayer/cisa-known-exploited-mirror/main/known_exploited_vulnerabilities.json</knownExploitedUrl> <knownExploitedUrl>
https://raw.githubusercontent.com/EugenMayer/cisa-known-exploited-mirror/main/known_exploited_vulnerabilities.json
</knownExploitedUrl>
<formats> <formats>
<format>html</format> <format>html</format>
<format>json</format> <format>json</format>
@@ -171,6 +172,23 @@
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.4.5</version>
<configuration>
<!-- Replace the main artifact (no classifier) -->
<classifier></classifier>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>

View File

@@ -5,12 +5,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import wtf.beatrice.hidekobot.datasources.ConfigurationEntry; import wtf.beatrice.hidekobot.datasources.ConfigurationEntry;
import wtf.beatrice.hidekobot.datasources.ConfigurationSource; import wtf.beatrice.hidekobot.datasources.ConfigurationSource;
import wtf.beatrice.hidekobot.datasources.DatabaseSource;
import wtf.beatrice.hidekobot.datasources.PropertiesSource; import wtf.beatrice.hidekobot.datasources.PropertiesSource;
import wtf.beatrice.hidekobot.listeners.MessageCommandListener; import wtf.beatrice.hidekobot.listeners.MessageCommandListener;
import wtf.beatrice.hidekobot.listeners.MessageLogger; import wtf.beatrice.hidekobot.listeners.MessageLogger;
import wtf.beatrice.hidekobot.listeners.SlashCommandCompletionListener; import wtf.beatrice.hidekobot.listeners.SlashCommandCompletionListener;
import wtf.beatrice.hidekobot.listeners.SlashCommandListener; import wtf.beatrice.hidekobot.listeners.SlashCommandListener;
import wtf.beatrice.hidekobot.util.Services;
import java.awt.*; import java.awt.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@@ -27,11 +27,22 @@ public class Cache
throw new IllegalStateException("Utility class"); throw new IllegalStateException("Utility class");
} }
// todo: make this compatible with the message listener's regex // todo: make this compatible with the message listener's regex
private static final String BOT_PREFIX = "hideko"; private static final String BOT_PREFIX = "hideko";
private static final Logger LOGGER = LoggerFactory.getLogger(Cache.class); 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 // map to store results of "love calculator", to avoid people re-running the same command until
// they get what they wanted. // they get what they wanted.
// i didn't think this was worthy of a whole database table with a runnable checking for expiration, // 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 PropertiesSource propertiesSource = null;
private static ConfigurationSource configurationSource = null; private static ConfigurationSource configurationSource = null;
private static DatabaseSource databaseSource = null;
private static boolean verbose = false; private static boolean verbose = false;
private static MessageLogger verbosityLogger = null; private static MessageLogger verbosityLogger = null;
private static final long BOT_MAINTAINER_ID = 979809420714332260L; private static final long BOT_MAINTAINER_ID = 979809420714332260L;
@@ -181,26 +191,6 @@ public class Cache
return DEFAULT_INVITE_LINK.replace("%userid%", botApplicationId); 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. * Set the properties source instance loaded from the JAR archive.
* *
@@ -244,7 +234,7 @@ public class Cache
*/ */
public static String getBotVersion() public static String getBotVersion()
{ {
return propertiesSource.getProperty("bot.version"); return propertiesSource.getProperty("bot.version").toLowerCase();
} }
/** /**

View File

@@ -6,20 +6,25 @@ import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.requests.GatewayIntent;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.context.ConfigurableApplicationContext;
import wtf.beatrice.hidekobot.commands.completer.ProfileImageCommandCompleter; import wtf.beatrice.hidekobot.commands.completer.ProfileImageCommandCompleter;
import wtf.beatrice.hidekobot.commands.message.HelloCommand; import wtf.beatrice.hidekobot.commands.message.*;
import wtf.beatrice.hidekobot.commands.slash.*; import wtf.beatrice.hidekobot.commands.slash.*;
import wtf.beatrice.hidekobot.datasources.ConfigurationSource; import wtf.beatrice.hidekobot.datasources.ConfigurationSource;
import wtf.beatrice.hidekobot.datasources.DatabaseSource;
import wtf.beatrice.hidekobot.datasources.PropertiesSource; import wtf.beatrice.hidekobot.datasources.PropertiesSource;
import wtf.beatrice.hidekobot.listeners.*; import wtf.beatrice.hidekobot.listeners.*;
import wtf.beatrice.hidekobot.runnables.ExpiredMessageTask; import wtf.beatrice.hidekobot.runnables.ExpiredMessageTask;
import wtf.beatrice.hidekobot.runnables.HeartBeatTask; import wtf.beatrice.hidekobot.runnables.HeartBeatTask;
import wtf.beatrice.hidekobot.runnables.RandomOrgSeedTask; import wtf.beatrice.hidekobot.runnables.RandomOrgSeedTask;
import wtf.beatrice.hidekobot.runnables.StatusUpdateTask; import wtf.beatrice.hidekobot.runnables.StatusUpdateTask;
import wtf.beatrice.hidekobot.util.CommandUtil; import wtf.beatrice.hidekobot.services.CommandService;
import wtf.beatrice.hidekobot.services.DatabaseService;
import wtf.beatrice.hidekobot.util.FormatUtil; import wtf.beatrice.hidekobot.util.FormatUtil;
import wtf.beatrice.hidekobot.util.RandomUtil; import wtf.beatrice.hidekobot.util.RandomUtil;
import wtf.beatrice.hidekobot.util.Services;
import java.io.File; import java.io.File;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -30,6 +35,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@SpringBootApplication
public class HidekoBot public class HidekoBot
{ {
private static JDA jda; private static JDA jda;
@@ -63,6 +69,18 @@ public class HidekoBot
return; return;
} }
ApplicationHome home = new ApplicationHome(HidekoBot.class);
System.setProperty("APP_HOME", home.getDir().getAbsolutePath());
ConfigurableApplicationContext context = SpringApplication.run(HidekoBot.class, args);
CommandService commandService = context.getBean(CommandService.class);
DatabaseService databaseService = context.getBean(DatabaseService.class);
Services services = new wtf.beatrice.hidekobot.util.Services(
commandService,
databaseService
);
Cache.setServices(services);
try try
{ {
// try to create the bot object and authenticate it with discord. // try to create the bot object and authenticate it with discord.
@@ -114,7 +132,6 @@ public class HidekoBot
} }
boolean enableRandomSeedUpdaterTask = false; boolean enableRandomSeedUpdaterTask = false;
// initialize random.org object if API key is provided // initialize random.org object if API key is provided
{ {
@@ -128,53 +145,55 @@ public class HidekoBot
} }
// register slash commands and completers // register slash commands and completers
SlashCommandListener slashCommandListener = new SlashCommandListener(); SlashCommandListener slashCommandListener = context.getBean(SlashCommandListener.class);
SlashCommandCompletionListener slashCommandCompletionListener = new SlashCommandCompletionListener(); SlashCommandCompletionListener slashCommandCompletionListener = context.getBean(SlashCommandCompletionListener.class);
AvatarCommand avatarCommand = new AvatarCommand(); MessageCommandListener messageCommandListener = context.getBean(MessageCommandListener.class);
ProfileImageCommandCompleter avatarCommandCompleter = new ProfileImageCommandCompleter(avatarCommand); ButtonInteractionListener buttonInteractionListener = context.getBean(ButtonInteractionListener.class);
slashCommandListener.registerCommand(avatarCommand); SelectMenuInteractionListener selectMenuInteractionListener = context.getBean(SelectMenuInteractionListener.class);
SlashAvatarCommand slashAvatarCommand = context.getBean(SlashAvatarCommand.class);
ProfileImageCommandCompleter avatarCommandCompleter = new ProfileImageCommandCompleter(slashAvatarCommand);
slashCommandListener.registerCommand(slashAvatarCommand);
slashCommandCompletionListener.registerCommandCompleter(avatarCommandCompleter); slashCommandCompletionListener.registerCommandCompleter(avatarCommandCompleter);
slashCommandListener.registerCommand(new BanCommand()); slashCommandListener.registerCommand(context.getBean(SlashBanCommand.class));
BannerCommand bannerCommand = new BannerCommand(); SlashBannerCommand slashBannerCommand = context.getBean(SlashBannerCommand.class);
ProfileImageCommandCompleter bannerCommandCompleter = new ProfileImageCommandCompleter(bannerCommand); ProfileImageCommandCompleter bannerCommandCompleter = new ProfileImageCommandCompleter(slashBannerCommand);
slashCommandListener.registerCommand(bannerCommand); slashCommandListener.registerCommand(slashBannerCommand);
slashCommandCompletionListener.registerCommandCompleter(bannerCommandCompleter); slashCommandCompletionListener.registerCommandCompleter(bannerCommandCompleter);
slashCommandListener.registerCommand(new BotInfoCommand()); slashCommandListener.registerCommand(context.getBean(SlashBotInfoCommand.class));
slashCommandListener.registerCommand(new ClearCommand()); slashCommandListener.registerCommand(context.getBean(SlashClearCommand.class));
slashCommandListener.registerCommand(new CoinFlipCommand()); slashCommandListener.registerCommand(context.getBean(SlashCoinFlipCommand.class));
slashCommandListener.registerCommand(new DiceRollCommand()); slashCommandListener.registerCommand(context.getBean(SlashDiceRollCommand.class));
slashCommandListener.registerCommand(new DieCommand()); slashCommandListener.registerCommand(new SlashDieCommand());
slashCommandListener.registerCommand(new HelpCommand()); slashCommandListener.registerCommand(new SlashHelpCommand());
slashCommandListener.registerCommand(new InviteCommand()); slashCommandListener.registerCommand(context.getBean(SlashInviteCommand.class));
slashCommandListener.registerCommand(new KickCommand()); slashCommandListener.registerCommand(context.getBean(SlashKickCommand.class));
slashCommandListener.registerCommand(new LoveCalculatorCommand()); slashCommandListener.registerCommand(context.getBean(SlashLoveCalculatorCommand.class));
slashCommandListener.registerCommand(new MagicBallCommand()); slashCommandListener.registerCommand(context.getBean(SlashMagicBallCommand.class));
slashCommandListener.registerCommand(new PingCommand()); slashCommandListener.registerCommand(new SlashPingCommand());
slashCommandListener.registerCommand(new SayCommand()); slashCommandListener.registerCommand(context.getBean(SlashSayCommand.class));
slashCommandListener.registerCommand(new TimeoutCommand()); slashCommandListener.registerCommand(context.getBean(SlashTimeoutCommand.class));
slashCommandListener.registerCommand(new TriviaCommand()); slashCommandListener.registerCommand(new SlashTriviaCommand());
slashCommandListener.registerCommand(new UrbanDictionaryCommand()); slashCommandListener.registerCommand(new SlashUrbanDictionaryCommand());
// register message commands // register message commands
MessageCommandListener messageCommandListener = new MessageCommandListener(); messageCommandListener.registerCommand(new MessageHelloCommand());
messageCommandListener.registerCommand(new HelloCommand()); messageCommandListener.registerCommand(context.getBean(MessageAliasCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.AliasCommand()); messageCommandListener.registerCommand(context.getBean(MessageAvatarCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.AvatarCommand()); messageCommandListener.registerCommand(context.getBean(MessageBanCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.BanCommand()); messageCommandListener.registerCommand(context.getBean(MessageBannerCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.BannerCommand()); messageCommandListener.registerCommand(context.getBean(MessageBotInfoCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.BotInfoCommand()); messageCommandListener.registerCommand(context.getBean(MessageCoinFlipCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.CoinFlipCommand()); messageCommandListener.registerCommand(context.getBean(MessageClearCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.ClearCommand()); messageCommandListener.registerCommand(context.getBean(MessageDiceRollCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.DiceRollCommand()); messageCommandListener.registerCommand(context.getBean(MessageHelpCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.HelpCommand()); messageCommandListener.registerCommand(context.getBean(MessageInviteCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.InviteCommand()); messageCommandListener.registerCommand(context.getBean(MessageKickCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.KickCommand()); messageCommandListener.registerCommand(context.getBean(MessageLoveCalculatorCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.LoveCalculatorCommand()); messageCommandListener.registerCommand(context.getBean(MessageMagicBallCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.MagicBallCommand()); messageCommandListener.registerCommand(context.getBean(MessageSayCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.SayCommand()); messageCommandListener.registerCommand(context.getBean(MessageTimeoutCommand.class));
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.TimeoutCommand()); messageCommandListener.registerCommand(new MessageTriviaCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.TriviaCommand()); messageCommandListener.registerCommand(new MessageUrbanDictionaryCommand());
messageCommandListener.registerCommand(new wtf.beatrice.hidekobot.commands.message.UrbanDictionaryCommand());
// register listeners // register listeners
Cache.setSlashCommandListener(slashCommandListener); Cache.setSlashCommandListener(slashCommandListener);
@@ -183,43 +202,28 @@ public class HidekoBot
jda.addEventListener(messageCommandListener); jda.addEventListener(messageCommandListener);
jda.addEventListener(slashCommandListener); jda.addEventListener(slashCommandListener);
jda.addEventListener(slashCommandCompletionListener); jda.addEventListener(slashCommandCompletionListener);
jda.addEventListener(new ButtonInteractionListener()); jda.addEventListener(buttonInteractionListener);
jda.addEventListener(new SelectMenuInteractionListener()); jda.addEventListener(selectMenuInteractionListener);
// update slash commands (delayed) // update slash commands (delayed)
final boolean finalForceUpdateCommands = forceUpdateCommands; final boolean finalForceUpdateCommands = forceUpdateCommands;
try (ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor()) try (ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor())
{ {
executor.schedule(() -> CommandUtil.updateSlashCommands(finalForceUpdateCommands), executor.schedule(() -> commandService.updateSlashCommands(finalForceUpdateCommands),
1, TimeUnit.SECONDS); 1, TimeUnit.SECONDS);
} }
// set the bot's status // set the bot's status
jda.getPresence().setStatus(OnlineStatus.ONLINE); 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 // start scheduled runnables
ScheduledExecutorService scheduler = Cache.getTaskScheduler(); ScheduledExecutorService scheduler = Cache.getTaskScheduler();
ExpiredMessageTask expiredMessageTask = new ExpiredMessageTask(); ExpiredMessageTask expiredMessageTask = new ExpiredMessageTask(services.databaseService(), services.commandService());
scheduler.scheduleAtFixedRate(expiredMessageTask, 5L, 5L, TimeUnit.SECONDS); //every 5 seconds scheduler.scheduleAtFixedRate(expiredMessageTask, 5L, 5L, TimeUnit.SECONDS); //every 5 seconds
HeartBeatTask heartBeatTask = new HeartBeatTask(); HeartBeatTask heartBeatTask = new HeartBeatTask();
scheduler.scheduleAtFixedRate(heartBeatTask, 10L, 30L, TimeUnit.SECONDS); //every 30 seconds scheduler.scheduleAtFixedRate(heartBeatTask, 10L, 30L, TimeUnit.SECONDS); //every 30 seconds
StatusUpdateTask statusUpdateTask = new StatusUpdateTask(); StatusUpdateTask statusUpdateTask = new StatusUpdateTask();
scheduler.scheduleAtFixedRate(statusUpdateTask, 0L, 60L * 5L, TimeUnit.SECONDS); // every 5 minutes scheduler.scheduleAtFixedRate(statusUpdateTask, 0L, 60L * 5L, TimeUnit.SECONDS); // every 5 minutes
if (enableRandomSeedUpdaterTask) if (enableRandomSeedUpdaterTask)

View File

@@ -1,17 +1,15 @@
package wtf.beatrice.hidekobot.commands.base; package wtf.beatrice.hidekobot.commands.base;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.LinkedList; import java.util.LinkedList;
@Component
public class Alias public class Alias
{ {
private Alias()
{
throw new IllegalStateException("Utility class");
}
public static String generateNiceAliases(MessageCommand command) public String generateNiceAliases(MessageCommand command)
{ {
LinkedList<String> aliases = command.getCommandLabels(); LinkedList<String> aliases = command.getCommandLabels();
StringBuilder aliasesStringBuilder = new StringBuilder(); StringBuilder aliasesStringBuilder = new StringBuilder();

View File

@@ -2,6 +2,7 @@ package wtf.beatrice.hidekobot.commands.base;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageEmbed;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.HidekoBot; import wtf.beatrice.hidekobot.HidekoBot;
import wtf.beatrice.hidekobot.util.FormatUtil; import wtf.beatrice.hidekobot.util.FormatUtil;
@@ -11,14 +12,11 @@ import java.lang.management.ManagementFactory;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.List; import java.util.List;
@Component
public class BotInfo public class BotInfo
{ {
private BotInfo()
{
throw new IllegalStateException("Utility class");
}
public static MessageEmbed generateEmbed(List<String> commandLabels) public MessageEmbed generateEmbed(List<String> commandLabels)
{ {
EmbedBuilder embedBuilder = new EmbedBuilder(); EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setColor(Cache.getBotColor()); embedBuilder.setColor(Cache.getBotColor());

View File

@@ -8,33 +8,30 @@ import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Component
public class ClearChat public class ClearChat
{ {
private ClearChat() public String getLabel()
{
throw new IllegalStateException("Utility class");
}
public static String getLabel()
{ {
return "clear"; return "clear";
} }
public static String getDescription() public String getDescription()
{ {
return "Clear the current channel's chat."; return "Clear the current channel's chat.";
} }
public static Permission getPermission() public Permission getPermission()
{ {
return Permission.MESSAGE_MANAGE; return Permission.MESSAGE_MANAGE;
} }
public static String checkDMs(Channel channel) public String checkDMs(Channel channel)
{ {
if (!(channel instanceof TextChannel)) if (!(channel instanceof TextChannel))
{ {
@@ -44,7 +41,7 @@ public class ClearChat
return null; return null;
} }
public static String checkDeleteAmount(int toDeleteAmount) public String checkDeleteAmount(int toDeleteAmount)
{ {
if (toDeleteAmount <= 0) if (toDeleteAmount <= 0)
{ {
@@ -54,7 +51,7 @@ public class ClearChat
return null; return null;
} }
public static int delete(int toDeleteAmount, public int delete(int toDeleteAmount,
long startingMessageId, long startingMessageId,
MessageChannel channel) MessageChannel channel)
{ {
@@ -158,13 +155,13 @@ public class ClearChat
return deleted; return deleted;
} }
public static Button getDismissButton() public Button getDismissButton()
{ {
return Button.primary("generic_dismiss", "Dismiss") return Button.primary("generic_dismiss", "Dismiss")
.withEmoji(Emoji.fromUnicode("")); .withEmoji(Emoji.fromUnicode(""));
} }
public static String parseAmount(int deleted) public String parseAmount(int deleted)
{ {
if (deleted < 1) if (deleted < 1)
@@ -180,7 +177,7 @@ public class ClearChat
} }
// cap the amount to avoid abuse. // cap the amount to avoid abuse.
public static int getMaxAmount() public int getMaxAmount()
{ {
return 1000; return 1000;
} }

View File

@@ -6,26 +6,23 @@ import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.util.RandomUtil; import wtf.beatrice.hidekobot.util.RandomUtil;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@Component
public class CoinFlip public class CoinFlip
{ {
public Button getReflipButton()
private CoinFlip()
{
throw new IllegalStateException("Utility class");
}
public static Button getReflipButton()
{ {
return Button.primary("coinflip_reflip", "Flip again") return Button.primary("coinflip_reflip", "Flip again")
.withEmoji(Emoji.fromUnicode("\uD83E\uDE99")); .withEmoji(Emoji.fromUnicode("\uD83E\uDE99"));
} }
public static String genRandom() public String genRandom()
{ {
int rand = RandomUtil.getRandomNumber(0, 1); int rand = RandomUtil.getRandomNumber(0, 1);
String msg; String msg;
@@ -41,34 +38,53 @@ public class CoinFlip
return msg; return msg;
} }
public static void buttonReFlip(ButtonInteractionEvent event) public void buttonReFlip(ButtonInteractionEvent event)
{ {
// check if the user interacting is the same one who ran the command // Ack ASAP to avoid 3s timeout
if (!(Cache.getDatabaseSource().isUserTrackedFor(event.getUser().getId(), event.getMessageId()))) event.deferEdit().queue(hook -> {
// Permission check **after** ack
if (!Cache.getServices().databaseService().isUserTrackedFor(event.getUser().getId(), event.getMessageId()))
{ {
event.reply("❌ You did not run this command!").setEphemeral(true).queue(); hook.sendMessage("❌ You did not run this command!").setEphemeral(true).queue();
return; return;
} }
// set old message's button as disabled // Disable all components on the original message
List<ActionRow> actionRows = event.getMessage().getActionRows(); List<ActionRow> oldRows = event.getMessage().getActionRows();
actionRows.set(0, actionRows.get(0).asDisabled()); List<ActionRow> disabledRows = new ArrayList<>(oldRows.size());
event.editComponents(actionRows).queue(); for (ActionRow row : oldRows)
// perform coin flip
event.getHook().sendMessage(genRandom())
.addActionRow(getReflipButton())
.queue((message) ->
{ {
// set the command as expiring and restrict it to the user who ran it disabledRows.add(row.asDisabled());
trackAndRestrict(message, event.getUser()); }
}, (error) -> { hook.editOriginalComponents(disabledRows).queue();
// Send a follow-up with a fresh button
hook.sendMessage(genRandom())
.addActionRow(getReflipButton())
.queue(msg -> trackAndRestrict(msg, event.getUser()), err -> {
});
}, failure -> {
// Rare: if we couldn't ack, try best-effort fallbacks
try
{
List<ActionRow> oldRows = event.getMessage().getActionRows();
List<ActionRow> disabledRows = new ArrayList<>(oldRows.size());
for (ActionRow row : oldRows) disabledRows.add(row.asDisabled());
event.getMessage().editMessageComponents(disabledRows).queue();
} catch (Exception ignored)
{
}
event.getChannel().sendMessage(genRandom())
.addActionRow(getReflipButton())
.queue(msg -> trackAndRestrict(msg, event.getUser()), err -> {
});
}); });
} }
public static void trackAndRestrict(Message replyMessage, User user) public void trackAndRestrict(Message replyMessage, User user)
{ {
Cache.getDatabaseSource().queueDisabling(replyMessage); Cache.getServices().databaseService().queueDisabling(replyMessage);
Cache.getDatabaseSource().trackRanCommandReply(replyMessage, user); Cache.getServices().databaseService().trackRanCommandReply(replyMessage, user);
} }
} }

View File

@@ -2,6 +2,7 @@ package wtf.beatrice.hidekobot.commands.base;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
import wtf.beatrice.hidekobot.objects.fun.Dice; import wtf.beatrice.hidekobot.objects.fun.Dice;
@@ -12,15 +13,11 @@ import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@Component
public class DiceRoll public class DiceRoll
{ {
private DiceRoll() public MessageResponse buildResponse(User author, String[] args)
{
throw new IllegalStateException("Utility class");
}
public static MessageResponse buildResponse(User author, String[] args)
{ {
LinkedHashMap<Dice, Integer> dicesToRoll = new LinkedHashMap<>(); LinkedHashMap<Dice, Integer> dicesToRoll = new LinkedHashMap<>();
String diceRegex = "d\\d+"; String diceRegex = "d\\d+";
@@ -129,7 +126,7 @@ public class DiceRoll
EmbedBuilder embedBuilder = new EmbedBuilder(); EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setColor(Cache.getBotColor()); embedBuilder.setColor(Cache.getBotColor());
embedBuilder.setAuthor(author.getAsTag(), null, author.getAvatarUrl()); embedBuilder.setAuthor(author.getName(), null, author.getAvatarUrl());
embedBuilder.setTitle("Dice Roll"); embedBuilder.setTitle("Dice Roll");
if (RandomUtil.isRandomOrgKeyValid()) if (RandomUtil.isRandomOrgKeyValid())

View File

@@ -4,18 +4,15 @@ import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.HidekoBot; import wtf.beatrice.hidekobot.HidekoBot;
@Component
public class Invite public class Invite
{ {
private Invite() public MessageEmbed generateEmbed()
{
throw new IllegalStateException("Utility class");
}
public static MessageEmbed generateEmbed()
{ {
EmbedBuilder embedBuilder = new EmbedBuilder(); EmbedBuilder embedBuilder = new EmbedBuilder();
@@ -33,7 +30,7 @@ public class Invite
return embedBuilder.build(); return embedBuilder.build();
} }
public static Button getInviteButton() public Button getInviteButton()
{ {
String inviteUrl = Cache.getInviteUrl(); String inviteUrl = Cache.getInviteUrl();
return Button.link(inviteUrl, "Invite " + Cache.getBotName()) return Button.link(inviteUrl, "Invite " + Cache.getBotName())

View File

@@ -3,20 +3,17 @@ package wtf.beatrice.hidekobot.commands.base;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.util.RandomUtil; import wtf.beatrice.hidekobot.util.RandomUtil;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@Component
public class LoveCalculator public class LoveCalculator
{ {
private LoveCalculator() public MessageEmbed buildEmbedAndCacheResult(User author, User user1, User user2)
{
throw new IllegalStateException("Utility class");
}
public static MessageEmbed buildEmbedAndCacheResult(User author, User user1, User user2)
{ {
String userId1 = user1.getId(); String userId1 = user1.getId();
String userId2 = user2.getId(); String userId2 = user2.getId();
@@ -38,7 +35,7 @@ public class LoveCalculator
EmbedBuilder embedBuilder = new EmbedBuilder(); EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setColor(Cache.getBotColor()); embedBuilder.setColor(Cache.getBotColor());
embedBuilder.setAuthor(author.getAsTag(), null, author.getAvatarUrl()); embedBuilder.setAuthor(author.getName(), null, author.getAvatarUrl());
embedBuilder.setTitle("Love Calculator"); embedBuilder.setTitle("Love Calculator");
embedBuilder.addField("\uD83D\uDC65 People", embedBuilder.addField("\uD83D\uDC65 People",

View File

@@ -3,6 +3,7 @@ package wtf.beatrice.hidekobot.commands.base;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.util.RandomUtil; import wtf.beatrice.hidekobot.util.RandomUtil;
@@ -11,20 +12,16 @@ import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@Component
public class MagicBall public class MagicBall
{ {
private MagicBall() public LinkedList<String> getLabels()
{
throw new IllegalStateException("Utility class");
}
public static LinkedList<String> getLabels()
{ {
return new LinkedList<>(Arrays.asList("8ball", "8b", "eightball", "magicball")); return new LinkedList<>(Arrays.asList("8ball", "8b", "eightball", "magicball"));
} }
private static final List<String> answers = new ArrayList<>( private final List<String> answers = new ArrayList<>(
Arrays.asList("It is certain.", Arrays.asList("It is certain.",
"It is decidedly so.", "It is decidedly so.",
"Without a doubt.", "Without a doubt.",
@@ -46,13 +43,13 @@ public class MagicBall
"Outlook not so good.", "Outlook not so good.",
"Very doubtful.")); "Very doubtful."));
public static String getRandomAnswer() public String getRandomAnswer()
{ {
int answerPos = RandomUtil.getRandomNumber(0, answers.size() - 1); int answerPos = RandomUtil.getRandomNumber(0, answers.size() - 1);
return answers.get(answerPos); return answers.get(answerPos);
} }
public static MessageEmbed generateEmbed(String question, User author) public MessageEmbed generateEmbed(String question, User author)
{ {
// add a question mark at the end, if missing. // add a question mark at the end, if missing.
// this might not always apply but it's fun // this might not always apply but it's fun
@@ -61,7 +58,7 @@ public class MagicBall
String answer = getRandomAnswer(); String answer = getRandomAnswer();
EmbedBuilder embedBuilder = new EmbedBuilder(); EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setAuthor(author.getAsTag(), null, author.getAvatarUrl()); embedBuilder.setAuthor(author.getName(), null, author.getAvatarUrl());
embedBuilder.setTitle("Magic Ball"); embedBuilder.setTitle("Magic Ball");
embedBuilder.setColor(Cache.getBotColor()); embedBuilder.setColor(Cache.getBotColor());
embedBuilder.addField("❓ Question", question, false); embedBuilder.addField("❓ Question", question, false);

View File

@@ -3,18 +3,15 @@ package wtf.beatrice.hidekobot.commands.base;
import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.utils.ImageProxy; import net.dv8tion.jda.api.utils.ImageProxy;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
@Component
public class ProfileImage public class ProfileImage
{ {
private ProfileImage() public int parseResolution(int resolution)
{
throw new IllegalStateException("Utility class");
}
public static int parseResolution(int resolution)
{ {
int[] acceptedSizes = Cache.getSupportedAvatarResolutions(); int[] acceptedSizes = Cache.getSupportedAvatarResolutions();
@@ -34,7 +31,7 @@ public class ProfileImage
return acceptedSizes[idx]; return acceptedSizes[idx];
} }
public static MessageResponse buildResponse(int resolution, User user, ImageType imageType) public MessageResponse buildResponse(int resolution, User user, ImageType imageType)
{ {
String imageTypeName = imageType.name().toLowerCase(); String imageTypeName = imageType.name().toLowerCase();
String resolutionString; String resolutionString;

View File

@@ -1,16 +1,12 @@
package wtf.beatrice.hidekobot.commands.base; package wtf.beatrice.hidekobot.commands.base;
import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.Permission;
import org.springframework.stereotype.Component;
@Component
public class Say public class Say
{ {
public Permission getPermission()
private Say()
{
throw new IllegalStateException("Utility class");
}
public static Permission getPermission()
{ {
return Permission.MESSAGE_MANAGE; return Permission.MESSAGE_MANAGE;
} }

View File

@@ -19,7 +19,6 @@ import wtf.beatrice.hidekobot.objects.fun.TriviaCategory;
import wtf.beatrice.hidekobot.objects.fun.TriviaQuestion; import wtf.beatrice.hidekobot.objects.fun.TriviaQuestion;
import wtf.beatrice.hidekobot.objects.fun.TriviaScore; import wtf.beatrice.hidekobot.objects.fun.TriviaScore;
import wtf.beatrice.hidekobot.runnables.TriviaTask; import wtf.beatrice.hidekobot.runnables.TriviaTask;
import wtf.beatrice.hidekobot.util.CommandUtil;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
@@ -27,9 +26,10 @@ import java.io.InputStreamReader;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -45,13 +45,13 @@ public class Trivia
private static final String TRIVIA_API_LINK = "https://opentdb.com/api.php?amount=10&type=multiple&category="; private static final String TRIVIA_API_LINK = "https://opentdb.com/api.php?amount=10&type=multiple&category=";
private static final String TRIVIA_API_CATEGORIES_LINK = "https://opentdb.com/api_category.php"; private static final String TRIVIA_API_CATEGORIES_LINK = "https://opentdb.com/api_category.php";
public static List<String> channelsRunningTrivia = new ArrayList<>(); public static List<String> channelsRunningTrivia = Collections.synchronizedList(new ArrayList<>());
// first string is the channelId, the list contain all users who responded there // first string is the channelId, the list contain all users who responded there
public static HashMap<String, List<String>> channelAndWhoResponded = new HashMap<>(); public static ConcurrentHashMap<String, List<String>> channelAndWhoResponded = new ConcurrentHashMap<>();
// first string is the channelId, the list contain all score records for that channel // first string is the channelId, the list contain all score records for that channel
public static HashMap<String, LinkedList<TriviaScore>> channelAndScores = new HashMap<>(); public static ConcurrentHashMap<String, LinkedList<TriviaScore>> channelAndScores = new ConcurrentHashMap<>();
public static String getTriviaLink(int categoryId) public static String getTriviaLink(int categoryId)
{ {
@@ -181,6 +181,8 @@ public class Trivia
public static void handleAnswer(ButtonInteractionEvent event, AnswerType answerType) public static void handleAnswer(ButtonInteractionEvent event, AnswerType answerType)
{ {
// Ack immediately with an ephemeral deferral to avoid 3s timeout
event.deferReply(true).queue(hook -> {
User user = event.getUser(); User user = event.getUser();
String channelId = event.getChannel().getId(); String channelId = event.getChannel().getId();
@@ -188,6 +190,7 @@ public class Trivia
{ {
LinkedList<TriviaScore> scores = channelAndScores.get(channelId); LinkedList<TriviaScore> scores = channelAndScores.get(channelId);
if (scores == null) scores = new LinkedList<>(); if (scores == null) scores = new LinkedList<>();
TriviaScore currentUserScore = null; TriviaScore currentUserScore = null;
for (TriviaScore score : scores) for (TriviaScore score : scores)
{ {
@@ -206,13 +209,12 @@ public class Trivia
if (answerType.equals(AnswerType.CORRECT)) if (answerType.equals(AnswerType.CORRECT))
{ {
// Public message in channel
event.reply(user.getAsMention() + " got it right! \uD83E\uDD73 (**+3**)").queue(); event.getChannel().sendMessage(user.getAsMention() + " got it right! \uD83E\uDD73 (**+3**)").queue();
currentUserScore.changeScore(3); currentUserScore.changeScore(3);
} else } else
{ {
event.reply("" + user.getAsMention() + ", that's not the right answer! (**-1**)").queue(); event.getChannel().sendMessage("" + user.getAsMention() + ", that's not the right answer! (**-1**)").queue();
currentUserScore.changeScore(-1); currentUserScore.changeScore(-1);
} }
@@ -220,14 +222,22 @@ public class Trivia
channelAndScores.put(channelId, scores); channelAndScores.put(channelId, scores);
} else } else
{ {
event.reply("☹️ " + user.getAsMention() + ", you can't answer twice!") // Show the warning **in the original ephemeral message**, then delete it after 5s.
.queue(interaction -> hook.editOriginal("☹️ " + user.getAsMention() + ", you can't answer twice!").queue(v ->
Cache.getTaskScheduler().schedule(() -> hook.deleteOriginal().queueAfter(3, TimeUnit.SECONDS, null, __ -> {
interaction.deleteOriginal().queue(), 3, TimeUnit.SECONDS)); })
} );
return; // don't run the generic cleanup below; we want the message visible for ~5s
} }
private static boolean trackResponse(User user, MessageChannel channel) // Clean up the ephemeral deferral (no visible ephemeral message left) for the normal path
hook.deleteOriginal().queue(null, __ -> {
});
}, __ -> {
});
}
private static synchronized boolean trackResponse(User user, MessageChannel channel)
{ {
String userId = user.getId(); String userId = user.getId();
String channelId = channel.getId(); String channelId = channel.getId();
@@ -252,15 +262,17 @@ public class Trivia
public static void handleMenuSelection(StringSelectInteractionEvent event) public static void handleMenuSelection(StringSelectInteractionEvent event)
{ {
// Ack immediately (ephemeral) so we can safely do DB/work
event.deferReply(true).queue(hook -> {
// check if the user interacting is the same one who ran the command // 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(); hook.sendMessage("❌ You did not run this command!").setEphemeral(true).queue();
return; return;
} }
// todo: we shouldn't use this method, since it messes with the database... look at coin reflip // Disable buttons on the original message via service (uses separate REST calls)
CommandUtil.disableExpired(event.getMessageId()); Cache.getServices().commandService().disableExpired(event.getMessageId());
SelectOption pickedOption = event.getInteraction().getSelectedOptions().get(0); SelectOption pickedOption = event.getInteraction().getSelectedOptions().get(0);
String categoryName = pickedOption.getLabel(); String categoryName = pickedOption.getLabel();
@@ -270,6 +282,12 @@ public class Trivia
TriviaCategory category = new TriviaCategory(categoryName, categoryId); TriviaCategory category = new TriviaCategory(categoryName, categoryId);
startTrivia(event, category); startTrivia(event, category);
// remove the ephemeral deferral to keep things clean
hook.deleteOriginal().queue(null, __ -> {
});
}, __ -> {
});
} }
public static void startTrivia(StringSelectInteractionEvent event, TriviaCategory category) public static void startTrivia(StringSelectInteractionEvent event, TriviaCategory category)
@@ -280,20 +298,19 @@ public class Trivia
if (Trivia.channelsRunningTrivia.contains(channel.getId())) if (Trivia.channelsRunningTrivia.contains(channel.getId()))
{ {
// todo nicer looking // Already running: inform ephemerally via hook (the interaction was deferred in the caller)
// todo: also what if the bot stops (database...?) event.getHook().sendMessage(Trivia.getTriviaAlreadyRunningError())
// todo: also what if the message is already deleted .setEphemeral(true)
Message err = event.reply("Trivia is already running here!").complete().retrieveOriginal().complete(); .queue(msg -> Cache.getTaskScheduler().schedule(() -> msg.delete().queue(), 10, TimeUnit.SECONDS));
Cache.getTaskScheduler().schedule(() -> err.delete().queue(), 10, TimeUnit.SECONDS);
return; return;
} else } else
{ {
// todo nicer looking // Public info that a new session is starting
event.reply("Starting new Trivia session!").queue(); channel.sendMessage("Starting new Trivia session!").queue();
} }
TriviaTask triviaTask = new TriviaTask(author, channel, category,
TriviaTask triviaTask = new TriviaTask(author, channel, category); Cache.getServices().databaseService(), Cache.getServices().commandService());
ScheduledFuture<?> future = ScheduledFuture<?> future =
Cache.getTaskScheduler().scheduleAtFixedRate(triviaTask, Cache.getTaskScheduler().scheduleAtFixedRate(triviaTask,
0, 0,

View File

@@ -14,7 +14,7 @@ import org.apache.commons.text.WordUtils;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.jsoup.select.Elements; import org.jsoup.select.Elements;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.datasources.DatabaseSource; import wtf.beatrice.hidekobot.services.DatabaseService;
import wtf.beatrice.hidekobot.util.SerializationUtil; import wtf.beatrice.hidekobot.util.SerializationUtil;
import java.util.ArrayList; import java.util.ArrayList;
@@ -88,7 +88,7 @@ public class UrbanDictionary
EmbedBuilder embedBuilder = new EmbedBuilder(); EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setColor(Cache.getBotColor()); embedBuilder.setColor(Cache.getBotColor());
embedBuilder.setTitle(term + ", on Urban Dictionary", url); embedBuilder.setTitle(term + ", on Urban Dictionary", url);
embedBuilder.setAuthor(author.getAsTag(), null, author.getAvatarUrl()); embedBuilder.setAuthor(author.getName(), null, author.getAvatarUrl());
embedBuilder.addField("\uD83D\uDCD6 Definition", search.getPlaintextMeanings().get(page), false); embedBuilder.addField("\uD83D\uDCD6 Definition", search.getPlaintextMeanings().get(page), false);
embedBuilder.addField("\uD83D\uDCAD Example", search.getPlaintextExamples().get(page), false); embedBuilder.addField("\uD83D\uDCAD Example", search.getPlaintextExamples().get(page), false);
embedBuilder.addField("\uD83D\uDCCC Submission", embedBuilder.addField("\uD83D\uDCCC Submission",
@@ -107,9 +107,9 @@ public class UrbanDictionary
public static void track(Message message, User user, UrbanSearch search, String sanitizedTerm) public static void track(Message message, User user, UrbanSearch search, String sanitizedTerm)
{ {
Cache.getDatabaseSource().queueDisabling(message); Cache.getServices().databaseService().queueDisabling(message);
Cache.getDatabaseSource().trackRanCommandReply(message, user); Cache.getServices().databaseService().trackRanCommandReply(message, user);
Cache.getDatabaseSource().trackUrban(search.getSerializedMeanings(), Cache.getServices().databaseService().trackUrban(search.getSerializedMeanings(),
search.getSerializedExamples(), search.getSerializedExamples(),
search.getSerializedContributors(), search.getSerializedContributors(),
search.getSerializedDates(), search.getSerializedDates(),
@@ -119,8 +119,9 @@ public class UrbanDictionary
public static void changePage(ButtonInteractionEvent event, ChangeType changeType) public static void changePage(ButtonInteractionEvent event, ChangeType changeType)
{ {
event.deferEdit().queue();
String messageId = event.getMessageId(); 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 // check if the user interacting is the same one who ran the command
if (!(database.isUserTrackedFor(event.getUser().getId(), messageId))) if (!(database.isUserTrackedFor(event.getUser().getId(), messageId)))
@@ -130,7 +131,7 @@ public class UrbanDictionary
} }
// get current page and calculate how many pages there are // 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 term = database.getUrbanTerm(messageId);
String url = generateUrl(term); String url = generateUrl(term);
@@ -180,7 +181,9 @@ public class UrbanDictionary
ActionRow currentRow = ActionRow.of(components); ActionRow currentRow = ActionRow.of(components);
// update the message // update the message
event.editComponents(currentRow).setEmbeds(updatedEmbed).queue(); event.getHook().editOriginalEmbeds(updatedEmbed)
.setComponents(currentRow)
.queue();
database.setUrbanPage(messageId, page); database.setUrbanPage(messageId, page);
database.resetExpiryTimestamp(messageId); database.resetExpiryTimestamp(messageId);
} }

View File

@@ -12,6 +12,7 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.HidekoBot; import wtf.beatrice.hidekobot.HidekoBot;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
@@ -24,18 +25,14 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@Component
public class UserPunishment public class UserPunishment
{ {
private UserPunishment()
{
throw new IllegalStateException("Utility class");
}
private static final Duration maxTimeoutDuration = Duration.of(28, ChronoUnit.DAYS); private static final Duration maxTimeoutDuration = Duration.of(28, ChronoUnit.DAYS);
private static final Duration minTimeoutDuration = Duration.of(30, ChronoUnit.SECONDS); private static final Duration minTimeoutDuration = Duration.of(30, ChronoUnit.SECONDS);
public static void handle(SlashCommandInteractionEvent event, PunishmentType punishmentType) public void handle(SlashCommandInteractionEvent event, PunishmentType punishmentType)
{ {
// this might take a sec // this might take a sec
event.deferReply().queue(); event.deferReply().queue();
@@ -92,7 +89,7 @@ public class UserPunishment
event.getHook().editOriginal(response.content()).queue(); event.getHook().editOriginal(response.content()).queue();
} }
public static void handle(MessageReceivedEvent event, String[] args, PunishmentType punishmentType) public void handle(MessageReceivedEvent event, String[] args, PunishmentType punishmentType)
{ {
Mentions msgMentions = event.getMessage().getMentions(); Mentions msgMentions = event.getMessage().getMentions();
List<IMentionable> mentions = msgMentions.getMentions(); List<IMentionable> mentions = msgMentions.getMentions();
@@ -109,7 +106,7 @@ public class UserPunishment
event.getMessage().reply(response.content()).queue(); event.getMessage().reply(response.content()).queue();
} }
public static MessageResponse getResponse(User author, public MessageResponse getResponse(User author,
PunishmentType punishmentType, PunishmentType punishmentType,
MessageChannelUnion channel, MessageChannelUnion channel,
List<IMentionable> mentions, List<IMentionable> mentions,
@@ -182,11 +179,14 @@ public class UserPunishment
case KICK -> punishmentAction = guild.kick(mentioned); case KICK -> punishmentAction = guild.kick(mentioned);
case TIMEOUT -> case TIMEOUT ->
{ {
if (args != null) // Ensure a duration argument is provided at index 1 (after mention/user)
if (args == null || args.length <= 1)
{ {
return new MessageResponse("Please specify a punishment duration!", null);
}
String durationStr = args[1]; String durationStr = args[1];
duration = FormatUtil.parseDuration(durationStr); duration = FormatUtil.parseDuration(durationStr);
}
boolean isDurationValid = true; boolean isDurationValid = true;
@@ -197,7 +197,7 @@ public class UserPunishment
if (minTimeoutDuration.compareTo(duration) > 0) isDurationValid = false; if (minTimeoutDuration.compareTo(duration) > 0) isDurationValid = false;
} }
if (duration == null || !isDurationValid) if (!isDurationValid)
{ {
// todo nicer looking with emojis // todo nicer looking with emojis
return new MessageResponse("Sorry, but the specified duration is invalid!", null); return new MessageResponse("Sorry, but the specified duration is invalid!", null);
@@ -222,7 +222,7 @@ public class UserPunishment
} }
if (!reason.isEmpty() && !reasonBuilder.isEmpty()) if (!reason.isEmpty() && !reasonBuilder.isEmpty())
punishmentAction.reason("[" + author.getAsTag() + "] " + reason); punishmentAction.reason("[" + author.getName() + "] " + reason);
try try
{ {
@@ -236,7 +236,7 @@ public class UserPunishment
EmbedBuilder embedBuilder = new EmbedBuilder(); EmbedBuilder embedBuilder = new EmbedBuilder();
embedBuilder.setAuthor(author.getAsTag(), null, author.getAvatarUrl()); embedBuilder.setAuthor(author.getName(), null, author.getAvatarUrl());
embedBuilder.setColor(Cache.getBotColor()); embedBuilder.setColor(Cache.getBotColor());
embedBuilder.setTitle("User " + punishmentType.getPastTense()); embedBuilder.setTitle("User " + punishmentType.getPastTense());

View File

@@ -4,6 +4,8 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.commands.base.Alias; import wtf.beatrice.hidekobot.commands.base.Alias;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
@@ -13,9 +15,17 @@ import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class AliasCommand implements MessageCommand @Component
public class MessageAliasCommand implements MessageCommand
{ {
private final Alias alias;
public MessageAliasCommand(@Autowired Alias alias)
{
this.alias = alias;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
{ {
@@ -73,7 +83,7 @@ public class AliasCommand implements MessageCommand
return; return;
} }
String aliases = Alias.generateNiceAliases(command); String aliases = alias.generateNiceAliases(command);
aliases = "Aliases for **" + command.getCommandLabels().get(0) + "**: " + aliases; aliases = "Aliases for **" + command.getCommandLabels().get(0) + "**: " + aliases;
event.getMessage() event.getMessage()

View File

@@ -6,6 +6,8 @@ import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.HidekoBot; import wtf.beatrice.hidekobot.HidekoBot;
import wtf.beatrice.hidekobot.commands.base.ProfileImage; import wtf.beatrice.hidekobot.commands.base.ProfileImage;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
@@ -16,8 +18,15 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class AvatarCommand implements MessageCommand @Component
public class MessageAvatarCommand implements MessageCommand
{ {
private final ProfileImage profileImage;
public MessageAvatarCommand(@Autowired ProfileImage profileImage)
{
this.profileImage = profileImage;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
@@ -74,7 +83,7 @@ public class AvatarCommand implements MessageCommand
try try
{ {
int givenRes = Integer.parseInt(arg); int givenRes = Integer.parseInt(arg);
resolution = ProfileImage.parseResolution(givenRes); resolution = profileImage.parseResolution(givenRes);
resFound = true; resFound = true;
break; break;
} catch (NumberFormatException ignored) } catch (NumberFormatException ignored)
@@ -84,7 +93,7 @@ public class AvatarCommand implements MessageCommand
} }
// fallback in case we didn't find any specified resolution // fallback in case we didn't find any specified resolution
if (!resFound) resolution = ProfileImage.parseResolution(512); if (!resFound) resolution = profileImage.parseResolution(512);
// check if someone is mentioned // check if someone is mentioned
Mentions mentions = event.getMessage().getMentions(); Mentions mentions = event.getMessage().getMentions();
@@ -101,7 +110,7 @@ public class AvatarCommand implements MessageCommand
if (user == null) user = event.getAuthor(); if (user == null) user = event.getAuthor();
// send a response // send a response
MessageResponse response = ProfileImage.buildResponse(resolution, user, ProfileImage.ImageType.AVATAR); MessageResponse response = profileImage.buildResponse(resolution, user, ProfileImage.ImageType.AVATAR);
if (response.content() != null) if (response.content() != null)
{ {
event.getMessage().reply(response.content()).queue(); event.getMessage().reply(response.content()).queue();

View File

@@ -4,6 +4,8 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.UserPunishment; import wtf.beatrice.hidekobot.commands.base.UserPunishment;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -13,8 +15,15 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class BanCommand implements MessageCommand @Component
public class MessageBanCommand implements MessageCommand
{ {
private final UserPunishment userPunishment;
public MessageBanCommand(@Autowired UserPunishment userPunishment)
{
this.userPunishment = userPunishment;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
@@ -59,6 +68,6 @@ public class BanCommand implements MessageCommand
@Override @Override
public void runCommand(MessageReceivedEvent event, String label, String[] args) public void runCommand(MessageReceivedEvent event, String label, String[] args)
{ {
UserPunishment.handle(event, args, UserPunishment.PunishmentType.BAN); userPunishment.handle(event, args, UserPunishment.PunishmentType.BAN);
} }
} }

View File

@@ -6,6 +6,8 @@ import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.HidekoBot; import wtf.beatrice.hidekobot.HidekoBot;
import wtf.beatrice.hidekobot.commands.base.ProfileImage; import wtf.beatrice.hidekobot.commands.base.ProfileImage;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
@@ -16,8 +18,15 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class BannerCommand implements MessageCommand @Component
public class MessageBannerCommand implements MessageCommand
{ {
private final ProfileImage profileImage;
public MessageBannerCommand(@Autowired ProfileImage profileImage)
{
this.profileImage = profileImage;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
@@ -74,7 +83,7 @@ public class BannerCommand implements MessageCommand
try try
{ {
int givenRes = Integer.parseInt(arg); int givenRes = Integer.parseInt(arg);
resolution = ProfileImage.parseResolution(givenRes); resolution = profileImage.parseResolution(givenRes);
resFound = true; resFound = true;
break; break;
} catch (NumberFormatException ignored) } catch (NumberFormatException ignored)
@@ -84,7 +93,7 @@ public class BannerCommand implements MessageCommand
} }
// fallback in case we didn't find any specified resolution // fallback in case we didn't find any specified resolution
if (!resFound) resolution = ProfileImage.parseResolution(512); if (!resFound) resolution = profileImage.parseResolution(512);
// check if someone is mentioned // check if someone is mentioned
Mentions mentions = event.getMessage().getMentions(); Mentions mentions = event.getMessage().getMentions();
@@ -101,7 +110,7 @@ public class BannerCommand implements MessageCommand
if (user == null) user = event.getAuthor(); if (user == null) user = event.getAuthor();
// send a response // send a response
MessageResponse response = ProfileImage.buildResponse(resolution, user, ProfileImage.ImageType.BANNER); MessageResponse response = profileImage.buildResponse(resolution, user, ProfileImage.ImageType.BANNER);
if (response.content() != null) if (response.content() != null)
{ {
event.getMessage().reply(response.content()).queue(); event.getMessage().reply(response.content()).queue();

View File

@@ -5,6 +5,8 @@ import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.commands.base.BotInfo; import wtf.beatrice.hidekobot.commands.base.BotInfo;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
@@ -14,9 +16,17 @@ import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class BotInfoCommand implements MessageCommand @Component
public class MessageBotInfoCommand implements MessageCommand
{ {
private final BotInfo botInfo;
public MessageBotInfoCommand(@Autowired BotInfo botInfo)
{
this.botInfo = botInfo;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
{ {
@@ -70,7 +80,7 @@ public class BotInfoCommand implements MessageCommand
} }
// send the list // send the list
MessageEmbed embed = BotInfo.generateEmbed(commandNames); MessageEmbed embed = botInfo.generateEmbed(commandNames);
event.getMessage().replyEmbeds(embed).queue(); event.getMessage().replyEmbeds(embed).queue();
} }
} }

View File

@@ -6,6 +6,8 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.commands.base.ClearChat; import wtf.beatrice.hidekobot.commands.base.ClearChat;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
@@ -15,19 +17,27 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class ClearCommand implements MessageCommand @Component
public class MessageClearCommand implements MessageCommand
{ {
private final ClearChat clearChat;
public MessageClearCommand(@Autowired ClearChat clearChat)
{
this.clearChat = clearChat;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
{ {
return new LinkedList<>(Collections.singletonList(ClearChat.getLabel())); return new LinkedList<>(Collections.singletonList(clearChat.getLabel()));
} }
@Override @Override
public List<Permission> getPermissions() public List<Permission> getPermissions()
{ {
return Collections.singletonList(ClearChat.getPermission()); return Collections.singletonList(clearChat.getPermission());
} }
@Override @Override
@@ -61,7 +71,7 @@ public class ClearCommand implements MessageCommand
public void runCommand(MessageReceivedEvent event, String label, String[] args) public void runCommand(MessageReceivedEvent event, String label, String[] args)
{ {
// check if user is trying to run command in dms. // check if user is trying to run command in dms.
String error = ClearChat.checkDMs(event.getChannel()); String error = clearChat.checkDMs(event.getChannel());
if (error != null) if (error != null)
{ {
event.getMessage().reply(error).queue(); event.getMessage().reply(error).queue();
@@ -83,9 +93,9 @@ public class ClearCommand implements MessageCommand
} }
// cap the amount to avoid abuse. // cap the amount to avoid abuse.
if (toDeleteAmount > ClearChat.getMaxAmount()) toDeleteAmount = 0; if (toDeleteAmount > clearChat.getMaxAmount()) toDeleteAmount = 0;
error = ClearChat.checkDeleteAmount(toDeleteAmount); error = clearChat.checkDeleteAmount(toDeleteAmount);
if (error != null) if (error != null)
{ {
event.getMessage().reply(error).queue(); event.getMessage().reply(error).queue();
@@ -96,20 +106,20 @@ public class ClearCommand implements MessageCommand
String content = "\uD83D\uDEA7 Clearing..."; String content = "\uD83D\uDEA7 Clearing...";
Message botMessage = event.getMessage().reply(content).complete(); Message botMessage = event.getMessage().reply(content).complete();
int deleted = ClearChat.delete(toDeleteAmount, int deleted = clearChat.delete(toDeleteAmount,
event.getMessageIdLong(), event.getMessageIdLong(),
event.getChannel()); event.getChannel());
// get a nicely formatted message that logs the deletion of messages. // get a nicely formatted message that logs the deletion of messages.
content = ClearChat.parseAmount(deleted); content = clearChat.parseAmount(deleted);
// edit the message text and attach a button. // edit the message text and attach a button.
Button dismiss = ClearChat.getDismissButton(); Button dismiss = clearChat.getDismissButton();
Message finalMessage = event.getChannel().sendMessage(content).setActionRow(dismiss).complete(); Message finalMessage = event.getChannel().sendMessage(content).setActionRow(dismiss).complete();
// add the message to database. // add the message to database.
Cache.getDatabaseSource().queueDisabling(finalMessage); Cache.getServices().databaseService().queueDisabling(finalMessage);
Cache.getDatabaseSource().trackRanCommandReply(finalMessage, event.getAuthor()); Cache.getServices().databaseService().trackRanCommandReply(finalMessage, event.getAuthor());
// delete the sender's message. // delete the sender's message.
event.getMessage().delete().queue(); event.getMessage().delete().queue();

View File

@@ -4,6 +4,8 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.CoinFlip; import wtf.beatrice.hidekobot.commands.base.CoinFlip;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -12,9 +14,17 @@ import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class CoinFlipCommand implements MessageCommand @Component
public class MessageCoinFlipCommand implements MessageCommand
{ {
private final CoinFlip coinFlip;
public MessageCoinFlipCommand(@Autowired CoinFlip coinFlip)
{
this.coinFlip = coinFlip;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
{ {
@@ -60,12 +70,12 @@ public class CoinFlipCommand implements MessageCommand
{ {
// perform coin flip // perform coin flip
event.getMessage().reply(CoinFlip.genRandom()) event.getMessage().reply(coinFlip.genRandom())
.addActionRow(CoinFlip.getReflipButton()) .addActionRow(coinFlip.getReflipButton())
.queue((message) -> .queue((message) ->
{ {
// set the command as expiring and restrict it to the user who ran it // set the command as expiring and restrict it to the user who ran it
CoinFlip.trackAndRestrict(message, event.getAuthor()); coinFlip.trackAndRestrict(message, event.getAuthor());
}, (error) -> { }, (error) -> {
}); });
} }

View File

@@ -4,6 +4,8 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.DiceRoll; import wtf.beatrice.hidekobot.commands.base.DiceRoll;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
@@ -13,8 +15,16 @@ import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class DiceRollCommand implements MessageCommand @Component
public class MessageDiceRollCommand implements MessageCommand
{ {
private final DiceRoll diceRoll;
public MessageDiceRollCommand(@Autowired DiceRoll diceRoll)
{
this.diceRoll = diceRoll;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
{ {
@@ -66,7 +76,7 @@ public class DiceRollCommand implements MessageCommand
public void runCommand(MessageReceivedEvent event, String label, String[] args) public void runCommand(MessageReceivedEvent event, String label, String[] args)
{ {
MessageResponse response = DiceRoll.buildResponse(event.getAuthor(), args); MessageResponse response = diceRoll.buildResponse(event.getAuthor(), args);
if (response.content() != null) if (response.content() != null)
{ {

View File

@@ -4,6 +4,7 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -11,7 +12,8 @@ import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class HelloCommand implements MessageCommand @Component
public class MessageHelloCommand implements MessageCommand
{ {
@Override @Override

View File

@@ -6,6 +6,8 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.apache.commons.text.WordUtils; import org.apache.commons.text.WordUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.commands.base.Alias; import wtf.beatrice.hidekobot.commands.base.Alias;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
@@ -13,9 +15,16 @@ import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.*; import java.util.*;
public class HelpCommand implements MessageCommand @Component
public class MessageHelpCommand implements MessageCommand
{ {
private final Alias alias;
public MessageHelpCommand(@Autowired Alias alias)
{
this.alias = alias;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
@@ -127,7 +136,7 @@ public class HelpCommand implements MessageCommand
if (internalUsage != null) usage += " " + internalUsage; if (internalUsage != null) usage += " " + internalUsage;
usage += "`"; usage += "`";
String aliases = Alias.generateNiceAliases(command); String aliases = alias.generateNiceAliases(command);
List<Permission> permissions = command.getPermissions(); List<Permission> permissions = command.getPermissions();
StringBuilder permissionsStringBuilder = new StringBuilder(); StringBuilder permissionsStringBuilder = new StringBuilder();

View File

@@ -7,6 +7,8 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.Invite; import wtf.beatrice.hidekobot.commands.base.Invite;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -15,8 +17,15 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class InviteCommand implements MessageCommand @Component
public class MessageInviteCommand implements MessageCommand
{ {
private final Invite invite;
public MessageInviteCommand(@Autowired Invite invite)
{
this.invite = invite;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
@@ -63,8 +72,8 @@ public class InviteCommand implements MessageCommand
{ {
MessageEmbed inviteEmbed = Invite.generateEmbed(); MessageEmbed inviteEmbed = invite.generateEmbed();
Button inviteButton = Invite.getInviteButton(); Button inviteButton = invite.getInviteButton();
// if this is a guild, don't spam the invite in public but DM it // if this is a guild, don't spam the invite in public but DM it
if (event.getChannelType().isGuild()) if (event.getChannelType().isGuild())

View File

@@ -4,6 +4,8 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.UserPunishment; import wtf.beatrice.hidekobot.commands.base.UserPunishment;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -13,8 +15,15 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class KickCommand implements MessageCommand @Component
public class MessageKickCommand implements MessageCommand
{ {
private final UserPunishment userPunishment;
public MessageKickCommand(@Autowired UserPunishment userPunishment)
{
this.userPunishment = userPunishment;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
@@ -59,6 +68,6 @@ public class KickCommand implements MessageCommand
@Override @Override
public void runCommand(MessageReceivedEvent event, String label, String[] args) public void runCommand(MessageReceivedEvent event, String label, String[] args)
{ {
UserPunishment.handle(event, args, UserPunishment.PunishmentType.KICK); userPunishment.handle(event, args, UserPunishment.PunishmentType.KICK);
} }
} }

View File

@@ -8,6 +8,8 @@ import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.HidekoBot; import wtf.beatrice.hidekobot.HidekoBot;
import wtf.beatrice.hidekobot.commands.base.LoveCalculator; import wtf.beatrice.hidekobot.commands.base.LoveCalculator;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
@@ -17,8 +19,15 @@ import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class LoveCalculatorCommand implements MessageCommand @Component
public class MessageLoveCalculatorCommand implements MessageCommand
{ {
private final LoveCalculator loveCalculator;
public MessageLoveCalculatorCommand(@Autowired LoveCalculator loveCalculator)
{
this.loveCalculator = loveCalculator;
}
@Override @Override
@@ -91,7 +100,7 @@ public class LoveCalculatorCommand implements MessageCommand
user2 = HidekoBot.getAPI().retrieveUserById(mentionedUserId).complete(); user2 = HidekoBot.getAPI().retrieveUserById(mentionedUserId).complete();
} }
MessageEmbed embed = LoveCalculator.buildEmbedAndCacheResult(event.getAuthor(), user1, user2); MessageEmbed embed = loveCalculator.buildEmbedAndCacheResult(event.getAuthor(), user1, user2);
event.getChannel().sendMessageEmbeds(embed).queue(); event.getChannel().sendMessageEmbeds(embed).queue();
} }

View File

@@ -4,6 +4,8 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.MagicBall; import wtf.beatrice.hidekobot.commands.base.MagicBall;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -11,13 +13,20 @@ import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class MagicBallCommand implements MessageCommand @Component
public class MessageMagicBallCommand implements MessageCommand
{ {
private final MagicBall magicBall;
public MessageMagicBallCommand(@Autowired MagicBall magicBall)
{
this.magicBall = magicBall;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
{ {
return MagicBall.getLabels(); return magicBall.getLabels();
} }
@Nullable @Nullable
@@ -75,6 +84,6 @@ public class MagicBallCommand implements MessageCommand
String question = questionBuilder.toString(); String question = questionBuilder.toString();
event.getChannel().sendMessageEmbeds(MagicBall.generateEmbed(question, event.getAuthor())).queue(); event.getChannel().sendMessageEmbeds(magicBall.generateEmbed(question, event.getAuthor())).queue();
} }
} }

View File

@@ -5,6 +5,8 @@ import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.Say; import wtf.beatrice.hidekobot.commands.base.Say;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -13,9 +15,16 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class SayCommand implements MessageCommand @Component
public class MessageSayCommand implements MessageCommand
{ {
private final Say say;
public MessageSayCommand(@Autowired Say say)
{
this.say = say;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
@@ -27,7 +36,7 @@ public class SayCommand implements MessageCommand
@Override @Override
public List<Permission> getPermissions() public List<Permission> getPermissions()
{ {
return Collections.singletonList(Say.getPermission()); return Collections.singletonList(say.getPermission());
} }
@Override @Override

View File

@@ -4,6 +4,8 @@ import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.UserPunishment; import wtf.beatrice.hidekobot.commands.base.UserPunishment;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -13,8 +15,15 @@ import java.util.Collections;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class TimeoutCommand implements MessageCommand @Component
public class MessageTimeoutCommand implements MessageCommand
{ {
private final UserPunishment userPunishment;
public MessageTimeoutCommand(@Autowired UserPunishment userPunishment)
{
this.userPunishment = userPunishment;
}
@Override @Override
public LinkedList<String> getCommandLabels() public LinkedList<String> getCommandLabels()
@@ -59,6 +68,6 @@ public class TimeoutCommand implements MessageCommand
@Override @Override
public void runCommand(MessageReceivedEvent event, String label, String[] args) public void runCommand(MessageReceivedEvent event, String label, String[] args)
{ {
UserPunishment.handle(event, args, UserPunishment.PunishmentType.TIMEOUT); userPunishment.handle(event, args, UserPunishment.PunishmentType.TIMEOUT);
} }
} }

View File

@@ -19,7 +19,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class TriviaCommand implements MessageCommand public class MessageTriviaCommand implements MessageCommand
{ {
@Override @Override
@@ -94,8 +94,8 @@ public class TriviaCommand implements MessageCommand
if (response.components() != null) responseAction = responseAction.addActionRow(response.components()); if (response.components() != null) responseAction = responseAction.addActionRow(response.components());
responseAction.queue(message -> { responseAction.queue(message -> {
Cache.getDatabaseSource().trackRanCommandReply(message, event.getAuthor()); Cache.getServices().databaseService().trackRanCommandReply(message, event.getAuthor());
Cache.getDatabaseSource().queueDisabling(message); Cache.getServices().databaseService().queueDisabling(message);
}); });
} }

View File

@@ -17,7 +17,7 @@ import java.io.IOException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class UrbanDictionaryCommand implements MessageCommand public class MessageUrbanDictionaryCommand implements MessageCommand
{ {
@Override @Override

View File

@@ -7,12 +7,21 @@ import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.ProfileImage; import wtf.beatrice.hidekobot.commands.base.ProfileImage;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class AvatarCommand extends SlashCommandImpl @Component
public class SlashAvatarCommand extends SlashCommandImpl
{ {
private final ProfileImage profileImage;
public SlashAvatarCommand(@NotNull ProfileImage profileImage)
{
this.profileImage = profileImage;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
@@ -44,13 +53,13 @@ public class AvatarCommand extends SlashCommandImpl
OptionMapping sizeArg = event.getOption("size"); OptionMapping sizeArg = event.getOption("size");
if (sizeArg != null) if (sizeArg != null)
{ {
resolution = ProfileImage.parseResolution(sizeArg.getAsInt()); resolution = profileImage.parseResolution(sizeArg.getAsInt());
} else } else
{ {
resolution = ProfileImage.parseResolution(512); resolution = profileImage.parseResolution(512);
} }
MessageResponse response = ProfileImage.buildResponse(resolution, user, ProfileImage.ImageType.AVATAR); MessageResponse response = profileImage.buildResponse(resolution, user, ProfileImage.ImageType.AVATAR);
if (response.content() != null) if (response.content() != null)
{ {
event.getHook().editOriginal(response.content()).queue(); event.getHook().editOriginal(response.content()).queue();

View File

@@ -7,11 +7,21 @@ import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.UserPunishment; import wtf.beatrice.hidekobot.commands.base.UserPunishment;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class BanCommand extends SlashCommandImpl @Component
public class SlashBanCommand extends SlashCommandImpl
{ {
private final UserPunishment userPunishment;
public SlashBanCommand(@Autowired UserPunishment userPunishment)
{
this.userPunishment = userPunishment;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
@@ -31,6 +41,6 @@ public class BanCommand extends SlashCommandImpl
@Override @Override
public void runSlashCommand(@NotNull SlashCommandInteractionEvent event) public void runSlashCommand(@NotNull SlashCommandInteractionEvent event)
{ {
UserPunishment.handle(event, UserPunishment.PunishmentType.BAN); userPunishment.handle(event, UserPunishment.PunishmentType.BAN);
} }
} }

View File

@@ -7,12 +7,21 @@ import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.ProfileImage; import wtf.beatrice.hidekobot.commands.base.ProfileImage;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class BannerCommand extends SlashCommandImpl @Component
public class SlashBannerCommand extends SlashCommandImpl
{ {
private final ProfileImage profileImage;
public SlashBannerCommand(@NotNull ProfileImage profileImage)
{
this.profileImage = profileImage;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
@@ -44,13 +53,13 @@ public class BannerCommand extends SlashCommandImpl
OptionMapping sizeArg = event.getOption("size"); OptionMapping sizeArg = event.getOption("size");
if (sizeArg != null) if (sizeArg != null)
{ {
resolution = ProfileImage.parseResolution(sizeArg.getAsInt()); resolution = profileImage.parseResolution(sizeArg.getAsInt());
} else } else
{ {
resolution = ProfileImage.parseResolution(512); resolution = profileImage.parseResolution(512);
} }
MessageResponse response = ProfileImage.buildResponse(resolution, user, ProfileImage.ImageType.BANNER); MessageResponse response = profileImage.buildResponse(resolution, user, ProfileImage.ImageType.BANNER);
if (response.content() != null) if (response.content() != null)
{ {
event.getHook().editOriginal(response.content()).queue(); event.getHook().editOriginal(response.content()).queue();

View File

@@ -5,6 +5,8 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEve
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.commands.base.BotInfo; import wtf.beatrice.hidekobot.commands.base.BotInfo;
import wtf.beatrice.hidekobot.objects.commands.SlashCommand; import wtf.beatrice.hidekobot.objects.commands.SlashCommand;
@@ -13,8 +15,17 @@ import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
public class BotInfoCommand extends SlashCommandImpl @Component
public class SlashBotInfoCommand extends SlashCommandImpl
{ {
private final BotInfo botInfo;
public SlashBotInfoCommand(@Autowired BotInfo botInfo)
{
this.botInfo = botInfo;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
@@ -37,7 +48,7 @@ public class BotInfoCommand extends SlashCommandImpl
} }
// send the list // send the list
MessageEmbed embed = BotInfo.generateEmbed(registeredCommandNames); MessageEmbed embed = botInfo.generateEmbed(registeredCommandNames);
event.getHook().editOriginalEmbeds(embed).queue(); event.getHook().editOriginalEmbeds(embed).queue();
} }
} }

View File

@@ -9,20 +9,29 @@ import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.Button;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.commands.base.ClearChat; import wtf.beatrice.hidekobot.commands.base.ClearChat;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class ClearCommand extends SlashCommandImpl @Component
public class SlashClearCommand extends SlashCommandImpl
{ {
private final ClearChat clearChat;
public SlashClearCommand(@Autowired ClearChat clearChat)
{
this.clearChat = clearChat;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
return Commands.slash(ClearChat.getLabel(), return Commands.slash(clearChat.getLabel(),
ClearChat.getDescription()) clearChat.getDescription())
.addOption(OptionType.INTEGER, "amount", "The amount of messages to delete.") .addOption(OptionType.INTEGER, "amount", "The amount of messages to delete.")
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(ClearChat.getPermission())); .setDefaultPermissions(DefaultMemberPermissions.enabledFor(clearChat.getPermission()));
} }
@Override @Override
@@ -32,7 +41,7 @@ public class ClearCommand extends SlashCommandImpl
event.deferReply().queue(); event.deferReply().queue();
// check if user is trying to run command in dms. // check if user is trying to run command in dms.
String error = ClearChat.checkDMs(event.getChannel()); String error = clearChat.checkDMs(event.getChannel());
if (error != null) if (error != null)
{ {
event.getHook().editOriginal(error).queue(); event.getHook().editOriginal(error).queue();
@@ -46,9 +55,9 @@ public class ClearCommand extends SlashCommandImpl
int toDeleteAmount = amountOption == null ? 1 : amountOption.getAsInt(); int toDeleteAmount = amountOption == null ? 1 : amountOption.getAsInt();
// cap the amount to avoid abuse. // cap the amount to avoid abuse.
if (toDeleteAmount > ClearChat.getMaxAmount()) toDeleteAmount = 0; if (toDeleteAmount > clearChat.getMaxAmount()) toDeleteAmount = 0;
error = ClearChat.checkDeleteAmount(toDeleteAmount); error = clearChat.checkDeleteAmount(toDeleteAmount);
if (error != null) if (error != null)
{ {
event.getHook().editOriginal(error).queue(); event.getHook().editOriginal(error).queue();
@@ -60,20 +69,20 @@ public class ClearCommand extends SlashCommandImpl
Message botMessage = event.getHook().editOriginal(content).complete(); Message botMessage = event.getHook().editOriginal(content).complete();
// actually delete the messages. // actually delete the messages.
int deleted = ClearChat.delete(toDeleteAmount, int deleted = clearChat.delete(toDeleteAmount,
event.getInteraction().getIdLong(), event.getInteraction().getIdLong(),
event.getChannel()); event.getChannel());
// get a nicely formatted message that logs the deletion of messages. // get a nicely formatted message that logs the deletion of messages.
content = ClearChat.parseAmount(deleted); content = clearChat.parseAmount(deleted);
// edit the message text and attach a button. // edit the message text and attach a button.
Button dismiss = ClearChat.getDismissButton(); Button dismiss = clearChat.getDismissButton();
botMessage = botMessage.editMessage(content).setActionRow(dismiss).complete(); botMessage = botMessage.editMessage(content).setActionRow(dismiss).complete();
// add the message to database. // add the message to database.
Cache.getDatabaseSource().queueDisabling(botMessage); Cache.getServices().databaseService().queueDisabling(botMessage);
Cache.getDatabaseSource().trackRanCommandReply(botMessage, event.getUser()); Cache.getServices().databaseService().trackRanCommandReply(botMessage, event.getUser());
} }
} }

View File

@@ -4,11 +4,20 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEve
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.CoinFlip; import wtf.beatrice.hidekobot.commands.base.CoinFlip;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class CoinFlipCommand extends SlashCommandImpl @Component
public class SlashCoinFlipCommand extends SlashCommandImpl
{ {
private final CoinFlip coinFlip;
public SlashCoinFlipCommand(@Autowired CoinFlip coinFlip)
{
this.coinFlip = coinFlip;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
@@ -21,14 +30,14 @@ public class CoinFlipCommand extends SlashCommandImpl
public void runSlashCommand(@NotNull SlashCommandInteractionEvent event) public void runSlashCommand(@NotNull SlashCommandInteractionEvent event)
{ {
// perform coin flip // perform coin flip
event.reply(CoinFlip.genRandom()) event.reply(coinFlip.genRandom())
.addActionRow(CoinFlip.getReflipButton()) .addActionRow(coinFlip.getReflipButton())
.queue((interaction) -> .queue((interaction) ->
{ {
// set the command as expiring and restrict it to the user who ran it // set the command as expiring and restrict it to the user who ran it
interaction.retrieveOriginal().queue((message) -> interaction.retrieveOriginal().queue((message) ->
{ {
CoinFlip.trackAndRestrict(message, event.getUser()); coinFlip.trackAndRestrict(message, event.getUser());
}, (error) -> { }, (error) -> {
}); });
}, (error) -> { }, (error) -> {

View File

@@ -6,12 +6,21 @@ import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.DiceRoll; import wtf.beatrice.hidekobot.commands.base.DiceRoll;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class DiceRollCommand extends SlashCommandImpl @Component
public class SlashDiceRollCommand extends SlashCommandImpl
{ {
private final DiceRoll diceRoll;
public SlashDiceRollCommand(@NotNull DiceRoll diceRoll)
{
this.diceRoll = diceRoll;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
@@ -37,7 +46,7 @@ public class DiceRollCommand extends SlashCommandImpl
String[] args = messageContent.split("\\s"); String[] args = messageContent.split("\\s");
MessageResponse response = DiceRoll.buildResponse(event.getUser(), args); MessageResponse response = diceRoll.buildResponse(event.getUser(), args);
if (response.content() != null) if (response.content() != null)
{ {

View File

@@ -13,7 +13,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class DieCommand extends SlashCommandImpl public class SlashDieCommand extends SlashCommandImpl
{ {
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()

View File

@@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class HelpCommand extends SlashCommandImpl public class SlashHelpCommand extends SlashCommandImpl
{ {
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()

View File

@@ -10,11 +10,19 @@ import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.restaction.WebhookMessageEditAction; import net.dv8tion.jda.api.requests.restaction.WebhookMessageEditAction;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.Invite; import wtf.beatrice.hidekobot.commands.base.Invite;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class InviteCommand extends SlashCommandImpl @Component
public class SlashInviteCommand extends SlashCommandImpl
{ {
private final Invite invite;
public SlashInviteCommand(@NotNull Invite invite)
{
this.invite = invite;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
@@ -36,8 +44,8 @@ public class InviteCommand extends SlashCommandImpl
} }
replyCallbackAction.queue(); replyCallbackAction.queue();
MessageEmbed inviteEmbed = Invite.generateEmbed(); MessageEmbed inviteEmbed = invite.generateEmbed();
Button inviteButton = Invite.getInviteButton(); Button inviteButton = invite.getInviteButton();
WebhookMessageEditAction<Message> reply = WebhookMessageEditAction<Message> reply =
event.getHook() event.getHook()

View File

@@ -7,11 +7,22 @@ import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.UserPunishment; import wtf.beatrice.hidekobot.commands.base.UserPunishment;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class KickCommand extends SlashCommandImpl @Component
public class SlashKickCommand extends SlashCommandImpl
{ {
private final UserPunishment userPunishment;
public SlashKickCommand(@Autowired UserPunishment userPunishment)
{
this.userPunishment = userPunishment;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
@@ -31,6 +42,6 @@ public class KickCommand extends SlashCommandImpl
@Override @Override
public void runSlashCommand(@NotNull SlashCommandInteractionEvent event) public void runSlashCommand(@NotNull SlashCommandInteractionEvent event)
{ {
UserPunishment.handle(event, UserPunishment.PunishmentType.KICK); userPunishment.handle(event, UserPunishment.PunishmentType.KICK);
} }
} }

View File

@@ -8,11 +8,20 @@ import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.LoveCalculator; import wtf.beatrice.hidekobot.commands.base.LoveCalculator;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class LoveCalculatorCommand extends SlashCommandImpl @Component
public class SlashLoveCalculatorCommand extends SlashCommandImpl
{ {
private final LoveCalculator loveCalculator;
public SlashLoveCalculatorCommand(@NotNull LoveCalculator loveCalculator)
{
this.loveCalculator = loveCalculator;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
@@ -57,7 +66,7 @@ public class LoveCalculatorCommand extends SlashCommandImpl
secondUser = event.getUser(); secondUser = event.getUser();
} }
MessageEmbed embed = LoveCalculator.buildEmbedAndCacheResult(event.getUser(), firstUser, secondUser); MessageEmbed embed = loveCalculator.buildEmbedAndCacheResult(event.getUser(), firstUser, secondUser);
event.replyEmbeds(embed).queue(); event.replyEmbeds(embed).queue();
} }
} }

View File

@@ -7,16 +7,25 @@ import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.MagicBall; import wtf.beatrice.hidekobot.commands.base.MagicBall;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class MagicBallCommand extends SlashCommandImpl @Component
public class SlashMagicBallCommand extends SlashCommandImpl
{ {
private final MagicBall magicBall;
public SlashMagicBallCommand(@NotNull MagicBall magicBall)
{
this.magicBall = magicBall;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
return Commands.slash(MagicBall.getLabels().get(0), return Commands.slash(magicBall.getLabels().get(0),
"Ask a question to the magic ball.") "Ask a question to the magic ball.")
.addOption(OptionType.STRING, "question", .addOption(OptionType.STRING, "question",
"The question to ask.", "The question to ask.",
@@ -43,7 +52,7 @@ public class MagicBallCommand extends SlashCommandImpl
return; return;
} }
MessageEmbed response = MagicBall.generateEmbed(question, event.getUser()); MessageEmbed response = magicBall.generateEmbed(question, event.getUser());
event.replyEmbeds(response).queue(); event.replyEmbeds(response).queue();
} }
} }

View File

@@ -6,7 +6,7 @@ import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class PingCommand extends SlashCommandImpl public class SlashPingCommand extends SlashCommandImpl
{ {
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()

View File

@@ -8,11 +8,20 @@ import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.Say; import wtf.beatrice.hidekobot.commands.base.Say;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class SayCommand extends SlashCommandImpl @Component
public class SlashSayCommand extends SlashCommandImpl
{ {
private final Say say;
public SlashSayCommand(@NotNull Say say)
{
this.say = say;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
@@ -22,7 +31,7 @@ public class SayCommand extends SlashCommandImpl
"The message to send.", "The message to send.",
true, true,
false) false)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Say.getPermission())); .setDefaultPermissions(DefaultMemberPermissions.enabledFor(say.getPermission()));
} }
@Override @Override

View File

@@ -7,11 +7,22 @@ import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData; import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.Commands;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.UserPunishment; import wtf.beatrice.hidekobot.commands.base.UserPunishment;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class TimeoutCommand extends SlashCommandImpl @Component
public class SlashTimeoutCommand extends SlashCommandImpl
{ {
private final UserPunishment userPunishment;
public SlashTimeoutCommand(@Autowired UserPunishment userPunishment)
{
this.userPunishment = userPunishment;
}
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
{ {
@@ -35,6 +46,6 @@ public class TimeoutCommand extends SlashCommandImpl
@Override @Override
public void runSlashCommand(@NotNull SlashCommandInteractionEvent event) public void runSlashCommand(@NotNull SlashCommandInteractionEvent event)
{ {
UserPunishment.handle(event, UserPunishment.PunishmentType.TIMEOUT); userPunishment.handle(event, UserPunishment.PunishmentType.TIMEOUT);
} }
} }

View File

@@ -11,7 +11,7 @@ import wtf.beatrice.hidekobot.commands.base.Trivia;
import wtf.beatrice.hidekobot.objects.MessageResponse; import wtf.beatrice.hidekobot.objects.MessageResponse;
import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl; import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
public class TriviaCommand extends SlashCommandImpl public class SlashTriviaCommand extends SlashCommandImpl
{ {
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()
@@ -44,8 +44,8 @@ public class TriviaCommand extends SlashCommandImpl
event.getHook().editOriginalEmbeds(response.embed()).setActionRow(response.components()).queue(message -> event.getHook().editOriginalEmbeds(response.embed()).setActionRow(response.components()).queue(message ->
{ {
Cache.getDatabaseSource().trackRanCommandReply(message, event.getUser()); Cache.getServices().databaseService().trackRanCommandReply(message, event.getUser());
Cache.getDatabaseSource().queueDisabling(message); Cache.getServices().databaseService().queueDisabling(message);
}); });
} }
} }

View File

@@ -17,7 +17,7 @@ import wtf.beatrice.hidekobot.objects.commands.SlashCommandImpl;
import java.io.IOException; import java.io.IOException;
public class UrbanDictionaryCommand extends SlashCommandImpl public class SlashUrbanDictionaryCommand extends SlashCommandImpl
{ {
@Override @Override
public CommandData getSlashCommandData() public CommandData getSlashCommandData()

View File

@@ -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<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,
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<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)
{
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;
}
}

View File

@@ -0,0 +1,77 @@
package wtf.beatrice.hidekobot.entities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "command_runners")
public class CommandRunner
{
@Id
@Column(name = "message_id", nullable = false)
private String messageId;
@Column(name = "guild_id", nullable = false)
private String guildId;
@Column(name = "channel_id", nullable = false)
private String channelId;
@Column(name = "user_id", nullable = false)
private String userId;
@Column(name = "channel_type", nullable = false)
private String channelType; // store JDA enum name
public String getMessageId()
{
return messageId;
}
public void setMessageId(String messageId)
{
this.messageId = messageId;
}
public String getGuildId()
{
return guildId;
}
public void setGuildId(String guildId)
{
this.guildId = guildId;
}
public String getChannelId()
{
return channelId;
}
public void setChannelId(String channelId)
{
this.channelId = channelId;
}
public String getUserId()
{
return userId;
}
public void setUserId(String userId)
{
this.userId = userId;
}
public String getChannelType()
{
return channelType;
}
public void setChannelType(String channelType)
{
this.channelType = channelType;
}
}

View File

@@ -0,0 +1,64 @@
package wtf.beatrice.hidekobot.entities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "pending_disabled_messages")
public class PendingDisabledMessage
{
@Id
@Column(name = "message_id", nullable = false)
private String messageId;
@Column(name = "guild_id", nullable = false)
private String guildId;
@Column(name = "channel_id", nullable = false)
private String channelId;
@Column(name = "expiry_timestamp", nullable = false)
private String expiryTimestamp; // keep as String to match your format for now
public String getMessageId()
{
return messageId;
}
public void setMessageId(String messageId)
{
this.messageId = messageId;
}
public String getGuildId()
{
return guildId;
}
public void setGuildId(String guildId)
{
this.guildId = guildId;
}
public String getChannelId()
{
return channelId;
}
public void setChannelId(String channelId)
{
this.channelId = channelId;
}
public String getExpiryTimestamp()
{
return expiryTimestamp;
}
public void setExpiryTimestamp(String expiryTimestamp)
{
this.expiryTimestamp = expiryTimestamp;
}
}

View File

@@ -0,0 +1,103 @@
package wtf.beatrice.hidekobot.entities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
@Entity
@Table(name = "urban_dictionary")
public class UrbanDictionaryEntry
{
@Id
@Column(name = "message_id", nullable = false)
private String messageId;
@Column(name = "page", nullable = false)
private Integer page;
@Column(name = "meanings", nullable = false, columnDefinition = "TEXT")
private String meanings;
@Column(name = "examples", nullable = false, columnDefinition = "TEXT")
private String examples;
@Column(name = "contributors", nullable = false, columnDefinition = "TEXT")
private String contributors;
@Column(name = "dates", nullable = false, columnDefinition = "TEXT")
private String dates;
@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;
}
}

View File

@@ -4,16 +4,28 @@ import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.CoinFlip; import wtf.beatrice.hidekobot.commands.base.CoinFlip;
import wtf.beatrice.hidekobot.commands.base.Trivia; import wtf.beatrice.hidekobot.commands.base.Trivia;
import wtf.beatrice.hidekobot.commands.base.UrbanDictionary; import wtf.beatrice.hidekobot.commands.base.UrbanDictionary;
import wtf.beatrice.hidekobot.util.CommandUtil; import wtf.beatrice.hidekobot.services.CommandService;
@Component
public class ButtonInteractionListener extends ListenerAdapter public class ButtonInteractionListener extends ListenerAdapter
{ {
private static final Logger LOGGER = LoggerFactory.getLogger(ButtonInteractionListener.class); private static final Logger LOGGER = LoggerFactory.getLogger(ButtonInteractionListener.class);
private final CommandService commandService;
private final CoinFlip coinFlip;
public ButtonInteractionListener(@Autowired CommandService commandService,
@Autowired CoinFlip coinFlip)
{
this.commandService = commandService;
this.coinFlip = coinFlip;
}
@Override @Override
public void onButtonInteraction(ButtonInteractionEvent event) public void onButtonInteraction(ButtonInteractionEvent event)
{ {
@@ -22,10 +34,10 @@ public class ButtonInteractionListener extends ListenerAdapter
{ {
// coinflip // coinflip
case "coinflip_reflip" -> CoinFlip.buttonReFlip(event); case "coinflip_reflip" -> coinFlip.buttonReFlip(event);
// generic dismiss button // generic dismiss button
case "generic_dismiss" -> CommandUtil.delete(event); case "generic_dismiss" -> commandService.deleteUserLinkedMessage(event);
// urban dictionary navigation // urban dictionary navigation
case "urban_nextpage" -> UrbanDictionary.changePage(event, UrbanDictionary.ChangeType.NEXT); case "urban_nextpage" -> UrbanDictionary.changePage(event, UrbanDictionary.ChangeType.NEXT);

View File

@@ -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.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.objects.commands.CommandCategory; import wtf.beatrice.hidekobot.objects.commands.CommandCategory;
import wtf.beatrice.hidekobot.objects.commands.MessageCommand; import wtf.beatrice.hidekobot.objects.commands.MessageCommand;
@@ -14,6 +15,7 @@ import wtf.beatrice.hidekobot.objects.comparators.MessageCommandAliasesComparato
import java.util.*; import java.util.*;
@Component
public class MessageCommandListener extends ListenerAdapter public class MessageCommandListener extends ListenerAdapter
{ {

View File

@@ -8,7 +8,9 @@ import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class MessageLogger extends ListenerAdapter public class MessageLogger extends ListenerAdapter
{ {
// this class only gets loaded as a listener if verbosity is set to true on startup. // this class only gets loaded as a listener if verbosity is set to true on startup.
@@ -22,7 +24,7 @@ public class MessageLogger extends ListenerAdapter
public void onMessageReceived(@NotNull MessageReceivedEvent event) public void onMessageReceived(@NotNull MessageReceivedEvent event)
{ {
String toLog = ""; String toLog = "";
String userName = event.getAuthor().getAsTag(); String userName = event.getAuthor().getName();
String message = event.getMessage().getContentDisplay(); String message = event.getMessage().getContentDisplay();
if (event.getChannel() instanceof TextChannel channel) if (event.getChannel() instanceof TextChannel channel)

View File

@@ -4,8 +4,10 @@ import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionE
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.commands.base.Trivia; import wtf.beatrice.hidekobot.commands.base.Trivia;
@Component
public class SelectMenuInteractionListener extends ListenerAdapter public class SelectMenuInteractionListener extends ListenerAdapter
{ {

View File

@@ -2,11 +2,13 @@ package wtf.beatrice.hidekobot.listeners;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.objects.commands.SlashArgumentsCompleter; import wtf.beatrice.hidekobot.objects.commands.SlashArgumentsCompleter;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.TreeMap; import java.util.TreeMap;
@Component
public class SlashCommandCompletionListener extends ListenerAdapter public class SlashCommandCompletionListener extends ListenerAdapter
{ {

View File

@@ -3,11 +3,13 @@ package wtf.beatrice.hidekobot.listeners;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import wtf.beatrice.hidekobot.objects.commands.SlashCommand; import wtf.beatrice.hidekobot.objects.commands.SlashCommand;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.TreeMap; import java.util.TreeMap;
@Component
public class SlashCommandListener extends ListenerAdapter public class SlashCommandListener extends ListenerAdapter
{ {

View File

@@ -31,7 +31,7 @@ public class TriviaScore
@Override @Override
public String toString() public String toString()
{ {
return "[" + user.getAsTag() + "," + score + "]"; return "[" + user.getName() + "," + score + "]";
} }
} }

View File

@@ -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<CommandRunner, String>
{
}

View File

@@ -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<PendingDisabledMessage, String>
{
}

View File

@@ -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<UrbanDictionaryEntry, String>
{
}

View File

@@ -3,8 +3,8 @@ package wtf.beatrice.hidekobot.runnables;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import wtf.beatrice.hidekobot.Cache; import wtf.beatrice.hidekobot.Cache;
import wtf.beatrice.hidekobot.datasources.DatabaseSource; import wtf.beatrice.hidekobot.services.CommandService;
import wtf.beatrice.hidekobot.util.CommandUtil; import wtf.beatrice.hidekobot.services.DatabaseService;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
@@ -13,16 +13,20 @@ import java.util.List;
public class ExpiredMessageTask implements Runnable public class ExpiredMessageTask implements Runnable
{ {
private final DatabaseService databaseService;
private final CommandService commandService;
private final DateTimeFormatter formatter; private final DateTimeFormatter formatter;
private static final Logger LOGGER = LoggerFactory.getLogger(ExpiredMessageTask.class); private static final Logger LOGGER = LoggerFactory.getLogger(ExpiredMessageTask.class);
private DatabaseSource databaseSource;
public ExpiredMessageTask() public ExpiredMessageTask(DatabaseService databaseService,
CommandService commandService)
{ {
this.databaseService = databaseService;
this.commandService = commandService;
String format = Cache.getExpiryTimestampFormat(); String format = Cache.getExpiryTimestampFormat();
formatter = DateTimeFormatter.ofPattern(format); formatter = DateTimeFormatter.ofPattern(format);
databaseSource = Cache.getDatabaseSource();
} }
@@ -30,10 +34,7 @@ public class ExpiredMessageTask implements Runnable
public void run() public void run()
{ {
databaseSource = Cache.getDatabaseSource(); List<String> expiringMessages = databaseService.getQueuedExpiringMessages();
if (databaseSource == null) return;
List<String> expiringMessages = Cache.getDatabaseSource().getQueuedExpiringMessages();
if (expiringMessages == null || expiringMessages.isEmpty()) return; if (expiringMessages == null || expiringMessages.isEmpty()) return;
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
@@ -43,11 +44,11 @@ public class ExpiredMessageTask implements Runnable
if (Cache.isVerbose()) LOGGER.info("expired check: {}", messageId); 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 if (expiryTimestamp == null || expiryTimestamp.isEmpty()) // if missing timestamp
{ {
// count it as already expired // count it as already expired
databaseSource.untrackExpiredMessage(messageId); databaseService.untrackExpiredMessage(messageId);
// move on to next message // move on to next message
continue; continue;
} }
@@ -57,7 +58,7 @@ public class ExpiredMessageTask implements Runnable
if (now.isAfter(expiryDate)) if (now.isAfter(expiryDate))
{ {
if (Cache.isVerbose()) LOGGER.info("expired: {}", messageId); if (Cache.isVerbose()) LOGGER.info("expired: {}", messageId);
CommandUtil.disableExpired(messageId); commandService.disableExpired(messageId);
} }
} }

View File

@@ -13,13 +13,18 @@ import wtf.beatrice.hidekobot.objects.comparators.TriviaScoreComparator;
import wtf.beatrice.hidekobot.objects.fun.TriviaCategory; import wtf.beatrice.hidekobot.objects.fun.TriviaCategory;
import wtf.beatrice.hidekobot.objects.fun.TriviaQuestion; import wtf.beatrice.hidekobot.objects.fun.TriviaQuestion;
import wtf.beatrice.hidekobot.objects.fun.TriviaScore; import wtf.beatrice.hidekobot.objects.fun.TriviaScore;
import wtf.beatrice.hidekobot.util.CommandUtil; import wtf.beatrice.hidekobot.services.CommandService;
import wtf.beatrice.hidekobot.services.DatabaseService;
import java.util.*; import java.util.*;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
public class TriviaTask implements Runnable public class TriviaTask implements Runnable
{ {
private final DatabaseService databaseService;
private final CommandService commandService;
private final User author; private final User author;
private final MessageChannel channel; private final MessageChannel channel;
@@ -33,11 +38,17 @@ public class TriviaTask implements Runnable
private int iteration = 0; private int iteration = 0;
public TriviaTask(User author, MessageChannel channel, TriviaCategory category) public TriviaTask(User author,
MessageChannel channel,
TriviaCategory category,
DatabaseService databaseService,
CommandService commandService)
{ {
this.author = author; this.author = author;
this.channel = channel; this.channel = channel;
this.category = category; this.category = category;
this.databaseService = databaseService;
this.commandService = commandService;
triviaJson = Trivia.fetchJson(Trivia.getTriviaLink(category.categoryId())); triviaJson = Trivia.fetchJson(Trivia.getTriviaLink(category.categoryId()));
questions = Trivia.parseQuestions(triviaJson); //todo: null check, rate limiting... questions = Trivia.parseQuestions(triviaJson); //todo: null check, rate limiting...
@@ -55,7 +66,7 @@ public class TriviaTask implements Runnable
if (previousMessage != null) if (previousMessage != null)
{ {
// todo: we shouldn't use this method, since it messes with the database... look at coin reflip // todo: we shouldn't use this method, since it messes with the database... look at coin reflip
CommandUtil.disableExpired(previousMessage.getId()); commandService.disableExpired(previousMessage.getId());
String previousCorrectAnswer = questions.get(iteration - 1).correctAnswer(); String previousCorrectAnswer = questions.get(iteration - 1).correctAnswer();
@@ -193,12 +204,12 @@ public class TriviaTask implements Runnable
.complete(); .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: ^ 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: 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: only stored in that table. this should be solved when we merge / fix the two main tables.
// todo: then, we can remove this instruction. // todo: then, we can remove this instruction.
Cache.getDatabaseSource().queueDisabling(previousMessage); databaseService.queueDisabling(previousMessage);
iteration++; iteration++;
} }

View File

@@ -1,4 +1,4 @@
package wtf.beatrice.hidekobot.util; package wtf.beatrice.hidekobot.services;
import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDA;
@@ -14,22 +14,26 @@ import net.dv8tion.jda.api.interactions.components.LayoutComponent;
import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.RestAction;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.Cache;
import wtf.beatrice.hidekobot.HidekoBot; import wtf.beatrice.hidekobot.HidekoBot;
import wtf.beatrice.hidekobot.datasources.DatabaseSource;
import wtf.beatrice.hidekobot.objects.commands.SlashCommand; import wtf.beatrice.hidekobot.objects.commands.SlashCommand;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class CommandUtil @Component
public class CommandService
{ {
private static final Logger LOGGER = LoggerFactory.getLogger(CommandUtil.class); private static final Logger LOGGER = LoggerFactory.getLogger(CommandService.class);
private CommandUtil() private final DatabaseService databaseService;
public CommandService(@Autowired DatabaseService databaseService)
{ {
throw new IllegalStateException("Utility class"); this.databaseService = databaseService;
} }
/** /**
@@ -38,18 +42,37 @@ public class CommandUtil
* *
* @param event the button interaction event. * @param event the button interaction event.
*/ */
public static void delete(ButtonInteractionEvent event) public void deleteUserLinkedMessage(ButtonInteractionEvent event)
{ {
// check if the user interacting is the same one who ran the command // 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(); event.reply("❌ You did not run this command!").setEphemeral(true).queue();
return; return;
} }
// delete the message // Acknowledge immediately so the interaction token stays valid
event.getInteraction().getMessage().delete().queue(); event.deferEdit().queue(hook -> {
// no need to manually untrack it from database, it will be purged on the next planned check. // Try deleting via the interaction webhook (works for original interaction responses)
hook.deleteOriginal().queue(
success -> { /* optional: databaseService.untrackExpiredMessage(event.getMessageId()); */ },
failure -> {
// Fallback to channel delete (works even if webhook token expired)
event.getChannel().deleteMessageById(event.getMessageId()).queue(
null,
__ -> { /* ignore if already deleted */ }
);
}
);
},
failure -> {
// If we failed to acknowledge (interaction already expired), try channel delete anyway
event.getChannel().deleteMessageById(event.getMessageId()).queue(
null,
__ -> { /* ignore if already deleted */ }
);
}
);
} }
@@ -60,7 +83,7 @@ public class CommandUtil
* *
* @param force a boolean specifying if the update should be forced even if no differences were found. * @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 // populate commands list from registered commands
@@ -160,48 +183,46 @@ public class CommandUtil
* *
* @param messageId the message id to disable. * @param messageId the message id to disable.
*/ */
public static void disableExpired(String messageId) public void disableExpired(String messageId)
{ {
DatabaseSource databaseSource = Cache.getDatabaseSource(); String channelId = databaseService.getQueuedExpiringMessageChannel(messageId);
String channelId = databaseSource.getQueuedExpiringMessageChannel(messageId);
// todo: warning, the following method + related if check are thread-locking. // 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. // 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; MessageChannel textChannel = null;
// this should never happen, but only message channels are supported. // this should never happen, but only message channels are supported.
if (!msgChannelType.isMessage()) if (!msgChannelType.isMessage())
{ {
databaseSource.untrackExpiredMessage(messageId); databaseService.untrackExpiredMessage(messageId);
return; return;
} }
// if this is a DM // if this is a DM
if (!(msgChannelType.isGuild())) if (!(msgChannelType.isGuild()))
{ {
String userId = databaseSource.getTrackedReplyUserId(messageId); String userId = databaseService.getTrackedReplyUserId(messageId);
User user = userId == null ? null : HidekoBot.getAPI().retrieveUserById(userId).complete(); User user = userId == null ? null : HidekoBot.getAPI().retrieveUserById(userId).complete();
if (user == null) if (user == null)
{ {
// if user is not found, consider it expired // if user is not found, consider it expired
// (deleted profile, or blocked the bot) // (deleted profile, or blocked the bot)
databaseSource.untrackExpiredMessage(messageId); databaseService.untrackExpiredMessage(messageId);
return; return;
} }
textChannel = user.openPrivateChannel().complete(); textChannel = user.openPrivateChannel().complete();
} else } else
{ {
String guildId = databaseSource.getQueuedExpiringMessageGuild(messageId); String guildId = databaseService.getQueuedExpiringMessageGuild(messageId);
Guild guild = guildId == null ? null : HidekoBot.getAPI().getGuildById(guildId); Guild guild = guildId == null ? null : HidekoBot.getAPI().getGuildById(guildId);
if (guild == null) if (guild == null)
{ {
// if guild is not found, consider it expired // if guild is not found, consider it expired
// (server was deleted or bot was kicked) // (server was deleted or bot was kicked)
databaseSource.untrackExpiredMessage(messageId); databaseService.untrackExpiredMessage(messageId);
return; return;
} }
textChannel = guild.getTextChannelById(channelId); textChannel = guild.getTextChannelById(channelId);
@@ -211,7 +232,7 @@ public class CommandUtil
{ {
// if channel is not found, count it as expired // if channel is not found, count it as expired
// (channel was deleted or bot permissions restricted) // (channel was deleted or bot permissions restricted)
databaseSource.untrackExpiredMessage(messageId); databaseService.untrackExpiredMessage(messageId);
return; return;
} }
@@ -224,7 +245,7 @@ public class CommandUtil
message -> { message -> {
if (message == null) if (message == null)
{ {
databaseSource.untrackExpiredMessage(messageId); databaseService.untrackExpiredMessage(messageId);
return; return;
} }
@@ -237,9 +258,9 @@ public class CommandUtil
} }
message.editMessageComponents(newComponents).queue(); message.editMessageComponents(newComponents).queue();
databaseSource.untrackExpiredMessage(messageId); databaseService.untrackExpiredMessage(messageId);
}, },
error -> databaseSource.untrackExpiredMessage(messageId)); error -> databaseService.untrackExpiredMessage(messageId));
} }
} }

View File

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

View File

@@ -1,71 +0,0 @@
package wtf.beatrice.hidekobot.util;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Deprecated(since = "0.5.16", forRemoval = true)
public class Logger<T>
{
// objects that we need to have for a properly formatted message
private final String className;
private final String format = "[%date% %time%] [%class%] %message%";
private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
// when initializing a new logger, save variables in that instance
public Logger(Class<T> logClass)
{
className = logClass.getSimpleName();
}
/**
* Logs a message to console, following a specific format.
*
* @param message the message to log
*/
public void log(String message)
{
LocalDateTime now = LocalDateTime.now();
String currentDate = dateFormatter.format(now);
String currentTime = timeFormatter.format(now);
logRaw(format
.replace("%date%", currentDate)
.replace("%time%", currentTime)
.replace("%class%", className)
.replace("%message%", message));
}
/**
* Logs a message to console, after delaying it.
*
* @param message the message to log
* @param delay the time to wait before logging, in seconds
*/
public void log(String message, int delay)
{
// create a new scheduled executor with an anonymous runnable...
//... after waiting <delay> seconds.
try (ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor())
{
executor.schedule(() -> log(message), delay, TimeUnit.SECONDS);
}
}
/**
* Prints a message to console without any formatting.
*
* @param message the message to log
*/
public void logRaw(String message)
{
System.out.println(message);
}
}

View File

@@ -0,0 +1,8 @@
package wtf.beatrice.hidekobot.util;
import wtf.beatrice.hidekobot.services.CommandService;
import wtf.beatrice.hidekobot.services.DatabaseService;
public record Services(CommandService commandService, DatabaseService databaseService)
{
}

View File

@@ -0,0 +1,8 @@
spring.datasource.url=jdbc:sqlite:${APP_HOME}/db.sqlite
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