From 8b451c6ee52fe4517e5d4cbff7cdd05f7a4ce456 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 1 Jul 2024 21:20:39 +0100 Subject: [PATCH] add message snipe feature --- pom.xml | 16 +++ .../cc/fascinated/bat/command/Category.java | 1 + .../fascinated/bat/common/ProfileHolder.java | 5 + .../cc/fascinated/bat/config/RedisConfig.java | 73 +++++++++++ .../fascinated/bat/event/EventListener.java | 21 +++ .../commands/server/MemberCountCommand.java | 1 - .../messagesnipe/MessageSnipeFeature.java | 123 ++++++++++++++++++ .../features/messagesnipe/SnipedMessage.java | 26 ++++ .../messagesnipe/command/ClearSubCommand.java | 36 +++++ .../command/DeletedSubCommand.java | 50 +++++++ .../command/MessageSnipeCommand.java | 19 +++ .../fascinated/bat/model/DiscordMessage.java | 49 +++++++ .../repository/DiscordMessageRepository.java | 9 ++ .../bat/service/DiscordMessageService.java | 95 ++++++++++++++ .../fascinated/bat/service/EventService.java | 32 ++++- src/main/resources/application.yml | 9 +- 16 files changed, 562 insertions(+), 3 deletions(-) create mode 100644 src/main/java/cc/fascinated/bat/config/RedisConfig.java create mode 100644 src/main/java/cc/fascinated/bat/features/messagesnipe/MessageSnipeFeature.java create mode 100644 src/main/java/cc/fascinated/bat/features/messagesnipe/SnipedMessage.java create mode 100644 src/main/java/cc/fascinated/bat/features/messagesnipe/command/ClearSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/messagesnipe/command/DeletedSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/messagesnipe/command/MessageSnipeCommand.java create mode 100644 src/main/java/cc/fascinated/bat/model/DiscordMessage.java create mode 100644 src/main/java/cc/fascinated/bat/repository/DiscordMessageRepository.java create mode 100644 src/main/java/cc/fascinated/bat/service/DiscordMessageService.java 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