diff --git a/pom.xml b/pom.xml
index ef6b956..591badd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -108,6 +108,22 @@
5.2.4
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ io.lettuce
+ lettuce-core
+
+
+
+
+ redis.clients
+ jedis
+
+
diff --git a/src/main/java/cc/fascinated/bat/command/Category.java b/src/main/java/cc/fascinated/bat/command/Category.java
index c60650f..304f4a0 100644
--- a/src/main/java/cc/fascinated/bat/command/Category.java
+++ b/src/main/java/cc/fascinated/bat/command/Category.java
@@ -18,6 +18,7 @@ public enum Category {
SERVER(Emoji.fromFormatted("U+1F5A5"), "Server", false),
UTILITY(Emoji.fromFormatted("U+1F6E0"), "Utility", false),
MUSIC(Emoji.fromFormatted("U+1F3B5"), "Music", false),
+ SNIPE(Emoji.fromFormatted("U+1F4A3"), "Snipe", false),
BEAT_SABER(Emoji.fromFormatted("U+1FA84"), "Beat Saber", false),
BOT_ADMIN(null, null, true);
diff --git a/src/main/java/cc/fascinated/bat/common/ProfileHolder.java b/src/main/java/cc/fascinated/bat/common/ProfileHolder.java
index 91eec2a..7fc8f87 100644
--- a/src/main/java/cc/fascinated/bat/common/ProfileHolder.java
+++ b/src/main/java/cc/fascinated/bat/common/ProfileHolder.java
@@ -4,6 +4,8 @@ import cc.fascinated.bat.BatApplication;
import lombok.Getter;
import lombok.SneakyThrows;
import org.bson.Document;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
@@ -13,6 +15,7 @@ import java.util.Map;
*/
@Getter
public abstract class ProfileHolder {
+ private static final Logger log = LoggerFactory.getLogger(ProfileHolder.class);
/**
* The profiles for the holder
*/
@@ -38,6 +41,8 @@ public abstract class ProfileHolder {
Serializable profile = getProfiles().get(clazz.getSimpleName());
if (profile == null) {
T newProfile = clazz.cast(clazz.getDeclaredConstructors()[0].newInstance());
+
+ log.info("instance of profiles: {}", document.get("profiles").getClass().getSimpleName());
Document profiles = document.get("profiles", new org.bson.Document());
Document profileDocument = (Document) profiles.get(clazz.getSimpleName());
diff --git a/src/main/java/cc/fascinated/bat/config/RedisConfig.java b/src/main/java/cc/fascinated/bat/config/RedisConfig.java
new file mode 100644
index 0000000..0f6aa3c
--- /dev/null
+++ b/src/main/java/cc/fascinated/bat/config/RedisConfig.java
@@ -0,0 +1,73 @@
+package cc.fascinated.bat.config;
+
+import lombok.NonNull;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+
+/**
+ * @author Fascinated (fascinated7)
+ */
+@Configuration
+@Log4j2(topic = "Redis")
+public class RedisConfig {
+ /**
+ * The Redis server host.
+ */
+ @Value("${spring.data.redis.host}")
+ private String host;
+
+ /**
+ * The Redis server port.
+ */
+ @Value("${spring.data.redis.port}")
+ private int port;
+
+ /**
+ * The Redis database index.
+ */
+ @Value("${spring.data.redis.database}")
+ private int database;
+
+ /**
+ * The optional Redis password.
+ */
+ @Value("${spring.data.redis.auth}")
+ private String auth;
+
+ /**
+ * Build the config to use for Redis.
+ *
+ * @return the config
+ * @see RedisTemplate for config
+ */
+ @Bean @NonNull
+ public RedisTemplate redisTemplate() {
+ RedisTemplate template = new RedisTemplate<>();
+ template.setConnectionFactory(jedisConnectionFactory());
+ return template;
+ }
+
+ /**
+ * Build the connection factory to use
+ * when making connections to Redis.
+ *
+ * @return the built factory
+ * @see JedisConnectionFactory for factory
+ */
+ @Bean @NonNull
+ public JedisConnectionFactory jedisConnectionFactory() {
+ log.info("Connecting to Redis at {}:{}/{}", host, port, database);
+ RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
+ config.setDatabase(database);
+ if (!auth.trim().isEmpty()) { // Auth with our provided password
+ log.info("Using auth...");
+ config.setPassword(auth);
+ }
+ return new JedisConnectionFactory(config);
+ }
+}
diff --git a/src/main/java/cc/fascinated/bat/event/EventListener.java b/src/main/java/cc/fascinated/bat/event/EventListener.java
index 15fe225..fa553a5 100644
--- a/src/main/java/cc/fascinated/bat/event/EventListener.java
+++ b/src/main/java/cc/fascinated/bat/event/EventListener.java
@@ -2,6 +2,7 @@ package cc.fascinated.bat.event;
import cc.fascinated.bat.model.BatGuild;
import cc.fascinated.bat.model.BatUser;
+import cc.fascinated.bat.model.DiscordMessage;
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberLeaderboardToken;
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberPlayerScoreToken;
import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberScoreToken;
@@ -12,7 +13,9 @@ import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameE
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
+import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.MessageUpdateEvent;
import net.dv8tion.jda.api.events.user.update.UserUpdateGlobalNameEvent;
/**
@@ -57,6 +60,24 @@ public interface EventListener {
default void onGuildMessageReceive(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageReceivedEvent event) {
}
+ /**
+ * Called when a user updates a message
+ *
+ * @param guild the guild that the message was updated in
+ * @param user the user that updated the message
+ */
+ default void onGuildMessageEdit(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageUpdateEvent event) {
+ }
+
+ /**
+ * Called when a user deletes a message
+ *
+ * @param guild the guild that the message was deleted in
+ * @param user the user that deleted the message
+ */
+ default void onGuildMessageDelete(@NonNull BatGuild guild, BatUser user, DiscordMessage message, @NonNull MessageDeleteEvent event) {
+ }
+
/**
* Called when a user selects a string
*
diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/server/MemberCountCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/server/MemberCountCommand.java
index 18d4523..8bbc8fd 100644
--- a/src/main/java/cc/fascinated/bat/features/base/commands/server/MemberCountCommand.java
+++ b/src/main/java/cc/fascinated/bat/features/base/commands/server/MemberCountCommand.java
@@ -8,7 +8,6 @@ import cc.fascinated.bat.common.NumberFormatter;
import cc.fascinated.bat.model.BatGuild;
import cc.fascinated.bat.model.BatUser;
import lombok.NonNull;
-import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.OnlineStatus;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
diff --git a/src/main/java/cc/fascinated/bat/features/messagesnipe/MessageSnipeFeature.java b/src/main/java/cc/fascinated/bat/features/messagesnipe/MessageSnipeFeature.java
new file mode 100644
index 0000000..892f8f4
--- /dev/null
+++ b/src/main/java/cc/fascinated/bat/features/messagesnipe/MessageSnipeFeature.java
@@ -0,0 +1,123 @@
+package cc.fascinated.bat.features.messagesnipe;
+
+import cc.fascinated.bat.command.Category;
+import cc.fascinated.bat.event.EventListener;
+import cc.fascinated.bat.features.Feature;
+import cc.fascinated.bat.features.messagesnipe.command.MessageSnipeCommand;
+import cc.fascinated.bat.model.BatGuild;
+import cc.fascinated.bat.model.BatUser;
+import cc.fascinated.bat.model.DiscordMessage;
+import cc.fascinated.bat.service.CommandService;
+import lombok.NonNull;
+import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.MessageUpdateEvent;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+/**
+ * @author Fascinated (fascinated7)
+ */
+@Component
+public class MessageSnipeFeature extends Feature implements EventListener {
+ /**
+ * The sniped messages for each guild
+ */
+ private static final Map> snipedMessages = new HashMap<>();
+
+ @Autowired
+ public MessageSnipeFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) {
+ super("Message Snipe", false, Category.SNIPE);
+
+ super.registerCommand(commandService, context.getBean(MessageSnipeCommand.class));
+ }
+
+ /**
+ * Clears the sniped messages for the given guild
+ *
+ * @param guild the guild
+ * @return if the sniped messages were cleared
+ */
+ public static boolean clearSnipedMessages(BatGuild guild) {
+ if (snipedMessages.containsKey(guild)) {
+ snipedMessages.remove(guild);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Gets the sniped messages for the given guild
+ *
+ * @param guild the guild
+ * @return the sniped messages for the given guild
+ */
+ public static SnipedMessage getDeletedMessage(BatGuild guild, String channelId) {
+ List messages = snipedMessages.getOrDefault(guild, new ArrayList<>());
+ for (SnipedMessage message : messages) {
+ if (message.getDeletedDate() != null // Check if the message was deleted
+ && message.getMessage().getChannel().getId().equals(channelId)) {
+ return message;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the sniped message with the given id
+ *
+ * @param guild the guild
+ * @param messageId the id of the message
+ * @return the sniped message with the given id
+ */
+ private SnipedMessage getSnipedMessage(BatGuild guild, String messageId) {
+ List messages = snipedMessages.getOrDefault(guild, new ArrayList<>());
+ for (SnipedMessage message : messages) {
+ if (message.getMessage().getId().equals(messageId)) {
+ return message;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onGuildMessageReceive(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageReceivedEvent event) {
+ if (event.getAuthor().isBot()) return;
+
+ List messages = snipedMessages.getOrDefault(guild, new ArrayList<>());
+ if (messages.size() >= 10) {
+ messages.remove(0);
+ }
+ messages.add(new SnipedMessage(event.getMessage(), null));
+ snipedMessages.put(guild, messages);
+ }
+
+ @Override
+ public void onGuildMessageDelete(@NonNull BatGuild guild, BatUser user, DiscordMessage message, @NonNull MessageDeleteEvent event) {
+ List messages = snipedMessages.getOrDefault(guild, new ArrayList<>());
+ if (messages.size() >= 10) {
+ messages.remove(0);
+ }
+ SnipedMessage snipedMessage = getSnipedMessage(guild, event.getMessageId());
+ if (snipedMessage == null) {
+ return;
+ }
+ snipedMessage.setDeletedDate(new Date());
+ }
+
+ @Override
+ public void onGuildMessageEdit(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageUpdateEvent event) {
+ List messages = snipedMessages.getOrDefault(guild, new ArrayList<>());
+ if (messages.size() >= 10) {
+ messages.remove(0);
+ }
+ SnipedMessage snipedMessage = getSnipedMessage(guild, event.getMessageId());
+ if (snipedMessage == null) {
+ return;
+ }
+ snipedMessage.setMessage(event.getMessage());
+ }
+}
diff --git a/src/main/java/cc/fascinated/bat/features/messagesnipe/SnipedMessage.java b/src/main/java/cc/fascinated/bat/features/messagesnipe/SnipedMessage.java
new file mode 100644
index 0000000..17ab757
--- /dev/null
+++ b/src/main/java/cc/fascinated/bat/features/messagesnipe/SnipedMessage.java
@@ -0,0 +1,26 @@
+package cc.fascinated.bat.features.messagesnipe;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import net.dv8tion.jda.api.entities.Message;
+
+import java.util.Date;
+
+/**
+ * @author Fascinated (fascinated7)
+ */
+@AllArgsConstructor
+@Getter
+@Setter
+public class SnipedMessage {
+ /**
+ * The message that was sniped
+ */
+ private Message message;
+
+ /**
+ * The date when the message was deleted
+ */
+ private Date deletedDate;
+}
diff --git a/src/main/java/cc/fascinated/bat/features/messagesnipe/command/ClearSubCommand.java b/src/main/java/cc/fascinated/bat/features/messagesnipe/command/ClearSubCommand.java
new file mode 100644
index 0000000..9018db0
--- /dev/null
+++ b/src/main/java/cc/fascinated/bat/features/messagesnipe/command/ClearSubCommand.java
@@ -0,0 +1,36 @@
+package cc.fascinated.bat.features.messagesnipe.command;
+
+import cc.fascinated.bat.command.BatSubCommand;
+import cc.fascinated.bat.command.CommandInfo;
+import cc.fascinated.bat.common.EmbedUtils;
+import cc.fascinated.bat.features.messagesnipe.MessageSnipeFeature;
+import cc.fascinated.bat.model.BatGuild;
+import cc.fascinated.bat.model.BatUser;
+import lombok.NonNull;
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
+import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Fascinated (fascinated7)
+ */
+@Component("messagesnipe:clear.sub")
+@CommandInfo(name = "clear", description = "Clears the known sniped messages for this guild", requiredPermissions = Permission.MESSAGE_MANAGE)
+public class ClearSubCommand extends BatSubCommand {
+ @Override
+ public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
+ boolean cleared = MessageSnipeFeature.clearSnipedMessages(guild);
+ if (!cleared) {
+ event.replyEmbeds(EmbedUtils.errorEmbed()
+ .setDescription("There are no messages to clear in this guild")
+ .build()).queue();
+ return;
+ }
+
+ event.replyEmbeds(EmbedUtils.successEmbed()
+ .setDescription("Successfully cleared the sniped messages for this guild")
+ .build()).queue();
+ }
+}
diff --git a/src/main/java/cc/fascinated/bat/features/messagesnipe/command/DeletedSubCommand.java b/src/main/java/cc/fascinated/bat/features/messagesnipe/command/DeletedSubCommand.java
new file mode 100644
index 0000000..1e38af6
--- /dev/null
+++ b/src/main/java/cc/fascinated/bat/features/messagesnipe/command/DeletedSubCommand.java
@@ -0,0 +1,50 @@
+package cc.fascinated.bat.features.messagesnipe.command;
+
+import cc.fascinated.bat.command.BatSubCommand;
+import cc.fascinated.bat.command.CommandInfo;
+import cc.fascinated.bat.common.EmbedUtils;
+import cc.fascinated.bat.features.messagesnipe.MessageSnipeFeature;
+import cc.fascinated.bat.features.messagesnipe.SnipedMessage;
+import cc.fascinated.bat.model.BatGuild;
+import cc.fascinated.bat.model.BatUser;
+import lombok.NonNull;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
+import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Fascinated (fascinated7)
+ */
+@Component
+@CommandInfo(name = "deleted", description = "Snipe the last deleted message in this channel")
+public class DeletedSubCommand extends BatSubCommand {
+ @Override
+ public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) {
+ SnipedMessage message = MessageSnipeFeature.getDeletedMessage(guild, channel.getId());
+ if (message == null) {
+ event.replyEmbeds(EmbedUtils.errorEmbed()
+ .setDescription("There are no deleted messages to snipe in this channel")
+ .build()).queue();
+ return;
+ }
+
+ User author = message.getMessage().getAuthor();
+ event.replyEmbeds(EmbedUtils.genericEmbed()
+ .setDescription("""
+ **Deleted Message Snipe**
+ ➜ Author: **%s** (%s)
+ ➜ Deleted:
+ ➜ Content:
+ ```
+ %s
+ ```
+ """.formatted(
+ author.getAsMention(),
+ author.getId(),
+ message.getDeletedDate().getTime() / 1000,
+ message.getMessage().getContentRaw()
+ )).build()).queue();
+ }
+}
diff --git a/src/main/java/cc/fascinated/bat/features/messagesnipe/command/MessageSnipeCommand.java b/src/main/java/cc/fascinated/bat/features/messagesnipe/command/MessageSnipeCommand.java
new file mode 100644
index 0000000..12f5484
--- /dev/null
+++ b/src/main/java/cc/fascinated/bat/features/messagesnipe/command/MessageSnipeCommand.java
@@ -0,0 +1,19 @@
+package cc.fascinated.bat.features.messagesnipe.command;
+
+import cc.fascinated.bat.command.BatCommand;
+import cc.fascinated.bat.command.CommandInfo;
+import lombok.NonNull;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Fascinated (fascinated7)
+ */
+@Component
+@CommandInfo(name = "snipe", description = "Snipe messages")
+public class MessageSnipeCommand extends BatCommand {
+ public MessageSnipeCommand(@NonNull ApplicationContext context) {
+ super.addSubCommand(context.getBean(DeletedSubCommand.class));
+ super.addSubCommand(context.getBean(ClearSubCommand.class));
+ }
+}
diff --git a/src/main/java/cc/fascinated/bat/model/DiscordMessage.java b/src/main/java/cc/fascinated/bat/model/DiscordMessage.java
new file mode 100644
index 0000000..50fcb77
--- /dev/null
+++ b/src/main/java/cc/fascinated/bat/model/DiscordMessage.java
@@ -0,0 +1,49 @@
+package cc.fascinated.bat.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.data.redis.core.RedisHash;
+
+/**
+ * @author Fascinated (fascinated7)
+ */
+@AllArgsConstructor
+@Getter @Setter
+@RedisHash(value = "DiscordMessage", timeToLive = 86400) // 24 hours
+public class DiscordMessage {
+ /**
+ * The snowflake ID of the message
+ */
+ private final String id;
+
+ /**
+ * The timestamp when the message was sent
+ */
+ private final long timestamp;
+
+ /**
+ * The snowflake ID of the channel the message was sent in
+ */
+ private final String channelId;
+
+ /**
+ * The snowflake ID of the guild the message was sent in
+ */
+ private final String guildId;
+
+ /**
+ * The snowflake ID of the author of the message
+ */
+ private final String authorId;
+
+ /**
+ * The content of the message
+ */
+ private String content;
+
+ /**
+ * Whether the message was deleted
+ */
+ private boolean deleted;
+}
diff --git a/src/main/java/cc/fascinated/bat/repository/DiscordMessageRepository.java b/src/main/java/cc/fascinated/bat/repository/DiscordMessageRepository.java
new file mode 100644
index 0000000..5af1603
--- /dev/null
+++ b/src/main/java/cc/fascinated/bat/repository/DiscordMessageRepository.java
@@ -0,0 +1,9 @@
+package cc.fascinated.bat.repository;
+
+import cc.fascinated.bat.model.DiscordMessage;
+import org.springframework.data.repository.CrudRepository;
+
+/**
+ * @author Fascinated (fascinated7)
+ */
+public interface DiscordMessageRepository extends CrudRepository {}
\ No newline at end of file
diff --git a/src/main/java/cc/fascinated/bat/service/DiscordMessageService.java b/src/main/java/cc/fascinated/bat/service/DiscordMessageService.java
new file mode 100644
index 0000000..fc4643d
--- /dev/null
+++ b/src/main/java/cc/fascinated/bat/service/DiscordMessageService.java
@@ -0,0 +1,95 @@
+package cc.fascinated.bat.service;
+
+import cc.fascinated.bat.event.EventListener;
+import cc.fascinated.bat.model.BatGuild;
+import cc.fascinated.bat.model.BatUser;
+import cc.fascinated.bat.model.DiscordMessage;
+import cc.fascinated.bat.repository.DiscordMessageRepository;
+import lombok.NonNull;
+import lombok.extern.log4j.Log4j2;
+import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
+import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.MessageUpdateEvent;
+import net.dv8tion.jda.api.hooks.ListenerAdapter;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+
+/**
+ * @author Fascinated (fascinated7)
+ */
+@Service
+@Log4j2
+@DependsOn("discordService")
+public class DiscordMessageService extends ListenerAdapter {
+ private final DiscordMessageRepository discordMessageRepository;
+ private final GuildService guildService;
+ private final UserService userService;
+
+ @Autowired
+ public DiscordMessageService(DiscordMessageRepository discordMessageRepository, @NonNull GuildService guildService,
+ @NonNull UserService userService) {
+ this.discordMessageRepository = discordMessageRepository;
+ this.guildService = guildService;
+ this.userService = userService;
+
+ DiscordService.JDA.addEventListener(this);
+ }
+
+ /**
+ * Gets the message with the given id
+ *
+ * @param messageId the id of the message
+ * @return the message with the given id
+ */
+ public DiscordMessage getMessage(String messageId) {
+ Optional optionalMessage = discordMessageRepository.findById(messageId);
+ return optionalMessage.orElse(null);
+ }
+
+ @Override
+ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
+ discordMessageRepository.save(new DiscordMessage(
+ event.getMessageId(),
+ event.getMessage().getTimeCreated().toInstant().toEpochMilli(),
+ event.getChannel().getId(),
+ event.getGuild().getId(),
+ event.getAuthor().getId(),
+ event.getMessage().getContentRaw(),
+ false
+ ));
+ }
+
+ @Override
+ public void onMessageUpdate(@NotNull MessageUpdateEvent event) {
+ Optional message = discordMessageRepository.findById(event.getMessageId());
+ if (message.isPresent()) {
+ DiscordMessage discordMessage = message.get();
+ if (discordMessage.getContent().equals(event.getMessage().getContentRaw())) {
+ return;
+ }
+ discordMessage.setContent(event.getMessage().getContentRaw());
+ discordMessageRepository.save(discordMessage);
+ }
+
+ BatGuild guild = guildService.getGuild(event.getGuild().getId());
+ BatUser user = userService.getUser(event.getAuthor().getId());
+ for (EventListener listener : EventService.LISTENERS) {
+ listener.onGuildMessageEdit(guild, user, event);
+ }
+ }
+
+ @Override
+ public void onMessageDelete(@NotNull MessageDeleteEvent event) {
+ Optional optionalMessage = discordMessageRepository.findById(event.getMessageId());
+ if (optionalMessage.isEmpty()) {
+ return;
+ }
+ DiscordMessage message = optionalMessage.get();
+ message.setDeleted(true);
+ discordMessageRepository.save(message);
+ }
+}
diff --git a/src/main/java/cc/fascinated/bat/service/EventService.java b/src/main/java/cc/fascinated/bat/service/EventService.java
index 13e3a50..ef7e867 100644
--- a/src/main/java/cc/fascinated/bat/service/EventService.java
+++ b/src/main/java/cc/fascinated/bat/service/EventService.java
@@ -3,6 +3,7 @@ package cc.fascinated.bat.service;
import cc.fascinated.bat.event.EventListener;
import cc.fascinated.bat.model.BatGuild;
import cc.fascinated.bat.model.BatUser;
+import cc.fascinated.bat.model.DiscordMessage;
import lombok.NonNull;
import lombok.extern.log4j.Log4j2;
import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent;
@@ -11,7 +12,9 @@ import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameE
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
+import net.dv8tion.jda.api.events.message.MessageDeleteEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
+import net.dv8tion.jda.api.events.message.MessageUpdateEvent;
import net.dv8tion.jda.api.events.user.update.UserUpdateGlobalNameEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.jetbrains.annotations.NotNull;
@@ -36,11 +39,14 @@ public class EventService extends ListenerAdapter {
public static final Set LISTENERS = new HashSet<>();
private final GuildService guildService;
private final UserService userService;
+ private final DiscordMessageService discordMessageService;
@Autowired
- public EventService(@NonNull GuildService guildService, @NonNull UserService userService, @NonNull ApplicationContext context) {
+ public EventService(@NonNull ApplicationContext context, @NonNull GuildService guildService, @NonNull UserService userService,
+ @NonNull DiscordMessageService discordMessageService) {
this.guildService = guildService;
this.userService = userService;
+ this.discordMessageService = discordMessageService;
DiscordService.JDA.addEventListener(this);
context.getBeansOfType(EventListener.class).values().forEach(this::registerListeners);
@@ -95,6 +101,30 @@ public class EventService extends ListenerAdapter {
}
}
+ @Override
+ public void onMessageUpdate(@NotNull MessageUpdateEvent event) {
+ if (event.getAuthor().isBot()) {
+ return;
+ }
+ BatGuild guild = guildService.getGuild(event.getGuild().getId());
+ BatUser user = userService.getUser(event.getAuthor().getId());
+
+ for (EventListener listener : LISTENERS) {
+ listener.onGuildMessageEdit(guild, user, event);
+ }
+ }
+
+ @Override
+ public void onMessageDelete(@NotNull MessageDeleteEvent event) {
+ BatGuild guild = guildService.getGuild(event.getGuild().getId());
+ DiscordMessage message = discordMessageService.getMessage(event.getMessageId());
+ BatUser user = message == null ? null : userService.getUser(message.getAuthorId());
+
+ for (EventListener listener : LISTENERS) {
+ listener.onGuildMessageDelete(guild, user, message, event);
+ }
+ }
+
@Override
public void onStringSelectInteraction(StringSelectInteractionEvent event) {
if (event.getUser().isBot()) {
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index a420698..aacd46b 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -27,4 +27,11 @@ spring:
mongodb:
uri: "mongodb://bat:p4$$w0rd@localhost:27017"
database: "bat"
- auto-index-creation: true # Automatically create collection indexes
\ No newline at end of file
+ auto-index-creation: true # Automatically create collection indexes
+
+ # Redis - This is used for caching
+ redis:
+ host: "localhost"
+ port: 6379
+ database: 0
+ auth: "" # Leave blank for no auth
\ No newline at end of file