From 048d2856f9b6df95ec431642cef96e8024c6bba0 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:10:02 +0100 Subject: [PATCH 01/33] impl reminders --- .../bat/features/reminder/Reminder.java | 47 ++++++ .../features/reminder/ReminderFeature.java | 81 ++++++++++ .../features/reminder/ReminderProfile.java | 143 ++++++++++++++++++ .../reminder/command/ClearSubCommand.java | 37 +++++ .../reminder/command/ListSubCommand.java | 46 ++++++ .../reminder/command/ReminderCommand.java | 22 +++ .../reminder/command/SetSubCommand.java | 80 ++++++++++ .../spotify/command/CurrentSubCommand.java | 5 +- .../cc/fascinated/bat/model/BatGuild.java | 10 ++ 9 files changed, 470 insertions(+), 1 deletion(-) create mode 100644 src/main/java/cc/fascinated/bat/features/reminder/Reminder.java create mode 100644 src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java create mode 100644 src/main/java/cc/fascinated/bat/features/reminder/ReminderProfile.java create mode 100644 src/main/java/cc/fascinated/bat/features/reminder/command/ClearSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/reminder/command/ListSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/reminder/command/ReminderCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/reminder/command/SetSubCommand.java diff --git a/src/main/java/cc/fascinated/bat/features/reminder/Reminder.java b/src/main/java/cc/fascinated/bat/features/reminder/Reminder.java new file mode 100644 index 0000000..5a10194 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/reminder/Reminder.java @@ -0,0 +1,47 @@ +package cc.fascinated.bat.features.reminder; + +import cc.fascinated.bat.service.DiscordService; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; + +import java.util.Date; + +/** + * @author Fascinated (fascinated7) + */ +@AllArgsConstructor @Getter +public class Reminder { + /** + * What we should remind the user of + */ + private final String reminder; + + /** + * The channel ID to send the reminder to + */ + private final String channelId; + + /** + * The date the reminder should end + */ + private final Date endDate; + + /** + * Check if the reminder is expired + * + * @return If the reminder is expired + */ + public boolean isExpired() { + return System.currentTimeMillis() >= endDate.getTime(); + } + + /** + * Get the channel to send the reminder to + * + * @return The channel + */ + public TextChannel getChannel() { + return DiscordService.JDA.getTextChannelById(channelId); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java b/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java new file mode 100644 index 0000000..0243bd8 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java @@ -0,0 +1,81 @@ +package cc.fascinated.bat.features.reminder; + +import cc.fascinated.bat.command.Category; +import cc.fascinated.bat.features.Feature; +import cc.fascinated.bat.features.reminder.command.ReminderCommand; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.service.CommandService; +import cc.fascinated.bat.service.DiscordService; +import cc.fascinated.bat.service.GuildService; +import lombok.NonNull; +import lombok.extern.log4j.Log4j2; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.DependsOn; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@Log4j2(topic = "Reminder Feature") +@DependsOn("discordService") +public class ReminderFeature extends Feature { + public static final int MAX_REMINDERS = 5; // 5 reminders + public static final long MAX_REMINDER_LENGTH = TimeUnit.DAYS.toMicros(7); // 7 days + + private final GuildService guildService; + + @Autowired + public ReminderFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService, @NonNull GuildService guildService) { + super("Reminder", true, Category.GENERAL); + this.guildService = guildService; + + super.registerCommand(commandService, context.getBean(ReminderCommand.class)); + } + + @Scheduled(cron = "*/30 * * * * *") + public void checkReminders() { + for (Guild guild : DiscordService.JDA.getGuilds()) { + BatGuild batGuild = guildService.getGuild(guild.getId()); + if (batGuild == null) { + continue; + } + + ReminderProfile reminderProfile = batGuild.getProfile(ReminderProfile.class); + if (reminderProfile == null) { + continue; + } + + for (Map.Entry> entry : reminderProfile.getReminders().entrySet()) { + User user = entry.getKey(); + List toRemove = new ArrayList<>(); + List reminders = entry.getValue(); + for (Reminder reminder : reminders) { + if (!reminder.isExpired()) { + continue; + } + + toRemove.add(reminder); + TextChannel channel = reminder.getChannel(); + if (channel != null) { + channel.sendMessage("Hey %s! ⏰ It's time for your reminder: %s".formatted( + user.getAsMention(), + reminder.getReminder() + )).queue(); + } + } + toRemove.forEach(reminder -> reminderProfile.removeReminder(user, reminder)); + } + } + } +} diff --git a/src/main/java/cc/fascinated/bat/features/reminder/ReminderProfile.java b/src/main/java/cc/fascinated/bat/features/reminder/ReminderProfile.java new file mode 100644 index 0000000..001153e --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/reminder/ReminderProfile.java @@ -0,0 +1,143 @@ +package cc.fascinated.bat.features.reminder; + +import cc.fascinated.bat.common.Serializable; +import cc.fascinated.bat.service.DiscordService; +import com.google.gson.Gson; +import lombok.Getter; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import org.bson.Document; + +import java.util.*; + +/** + * @author Fascinated (fascinated7) + */ +@Getter +public class ReminderProfile extends Serializable { + /** + * The reminders in the guild + */ + private final Map> reminders = new HashMap<>(); + + /* + * Get the amount of reminders a user has + * + * @param user The user to get the reminders for + * @return The amount of reminders the user has + */ + public int getReminderCount(User user) { + List reminderList = reminders.get(user); + return reminderList == null ? 0 : reminderList.size(); + } + + /* + * Remove all reminders for a user + * + * @param user The user to remove the reminders for + */ + public void removeReminders(User user) { + reminders.remove(user); + } + + /* + * Check if a user has reminders + * + * @param user The user to check for + * @return If the user has reminders + */ + public boolean hasReminders(User user) { + return reminders.containsKey(user); + } + + /* + * Get the reminders for a user + * + * @param user The user to get the reminders for + * @return The reminders for the user + */ + public List getReminders(User user) { + return reminders.get(user); + } + + /* + * Add a reminder for a user + * + * @param user The user to add the reminder for + * @param reminder The reminder to add + */ + public Reminder addReminder(User user, TextChannel channel, String reason, Date endDate) { + List reminderList = reminders.get(user); + if (reminderList == null) { + reminderList = new ArrayList<>(); + } + Reminder reminder = new Reminder(reason, channel.getId(), endDate); + reminderList.add(reminder); + reminders.put(user, reminderList); + return reminder; + } + + /* + * Remove a reminder for a user + * + * @param user The user to remove the reminder for + * @param reminder The reminder to remove + */ + public void removeReminder(User user, Reminder reminder) { + List reminderList = reminders.get(user); + if (reminderList == null) { + return; + } + reminderList.remove(reminder); + reminders.put(user, reminderList); + + if (reminderList.isEmpty()) { + reminders.remove(user); + } + } + + @Override + public void load(Document document, Gson gson) { + for (String key : document.keySet()) { + User user = DiscordService.JDA.getUserById(key); + if (user == null) { + continue; + } + List reminderList = new ArrayList<>(); + for (Document reminderDocument : document.getList(key, Document.class)) { + reminderList.add(new Reminder( + reminderDocument.getString("reminder"), + reminderDocument.getString("channelId"), + reminderDocument.getDate("endDate") + )); + } + reminders.put(user, reminderList); + } + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + for (Map.Entry> entry : reminders.entrySet()) { + List reminderDocuments = new ArrayList<>(); + List value = entry.getValue(); + if (value == null || value.isEmpty()) { + continue; + } + for (Reminder reminder : value) { + Document reminderDocument = new Document(); + reminderDocument.append("reminder", reminder.getReminder()); + reminderDocument.append("channelId", reminder.getChannelId()); + reminderDocument.append("endDate", reminder.getEndDate()); + reminderDocuments.add(reminderDocument); + } + document.append(entry.getKey().getId(), reminderDocuments); + } + return document; + } + + @Override + public void reset() { + reminders.clear(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/reminder/command/ClearSubCommand.java b/src/main/java/cc/fascinated/bat/features/reminder/command/ClearSubCommand.java new file mode 100644 index 0000000..4977bf3 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/reminder/command/ClearSubCommand.java @@ -0,0 +1,37 @@ +package cc.fascinated.bat.features.reminder.command; + +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.reminder.ReminderProfile; +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.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("reminder:clear.sub") +@CommandInfo(name = "clear", description = "Clear all your active reminders.") +public class ClearSubCommand extends BatSubCommand { + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + ReminderProfile profile = guild.getReminderProfile(); + if (!profile.hasReminders(user.getDiscordUser())) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You do not have any active reminders.") + .build()).queue(); + return; + } + int reminderCount = profile.getReminderCount(user.getDiscordUser()); + profile.removeReminders(user.getDiscordUser()); + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription("Successfully cleared %s reminders.".formatted(reminderCount)) + .build() + ).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/reminder/command/ListSubCommand.java b/src/main/java/cc/fascinated/bat/features/reminder/command/ListSubCommand.java new file mode 100644 index 0000000..76f76c2 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/reminder/command/ListSubCommand.java @@ -0,0 +1,46 @@ +package cc.fascinated.bat.features.reminder.command; + +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.reminder.Reminder; +import cc.fascinated.bat.features.reminder.ReminderProfile; +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.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("reminder:list.sub") +@CommandInfo(name = "list", description = "View your active reminders.") +public class ListSubCommand extends BatSubCommand { + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + ReminderProfile profile = guild.getReminderProfile(); + if (!profile.hasReminders(user.getDiscordUser())) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You do not have any active reminders.") + .build()).queue(); + return; + } + + EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Active Reminders"); + for (Reminder reminder : profile.getReminders(user.getDiscordUser())) { + description.appendLine("%s - %s".formatted( + reminder.getReminder(), + reminder.getEndDate().toInstant().getEpochSecond(), + reminder.getChannel().getAsMention() + ), true); + } + event.replyEmbeds(EmbedUtils.genericEmbed() + .setDescription(description.build()) + .build() + ).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/reminder/command/ReminderCommand.java b/src/main/java/cc/fascinated/bat/features/reminder/command/ReminderCommand.java new file mode 100644 index 0000000..ba51e30 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/reminder/command/ReminderCommand.java @@ -0,0 +1,22 @@ +package cc.fascinated.bat.features.reminder.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import lombok.NonNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo(name = "reminder", description = "Set or view reminders.") +public class ReminderCommand extends BatCommand { + @Autowired + public ReminderCommand(@NonNull ApplicationContext context) { + super.addSubCommand(context.getBean(SetSubCommand.class)); + super.addSubCommand(context.getBean(ListSubCommand.class)); + super.addSubCommand(context.getBean(ClearSubCommand.class)); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/reminder/command/SetSubCommand.java b/src/main/java/cc/fascinated/bat/features/reminder/command/SetSubCommand.java new file mode 100644 index 0000000..7fca81c --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/reminder/command/SetSubCommand.java @@ -0,0 +1,80 @@ +package cc.fascinated.bat.features.reminder.command; + +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.common.TimeUtils; +import cc.fascinated.bat.features.reminder.Reminder; +import cc.fascinated.bat.features.reminder.ReminderFeature; +import cc.fascinated.bat.features.reminder.ReminderProfile; +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.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * @author Fascinated (fascinated7) + */ +@Component("reminder:set.sub") +@CommandInfo(name = "set", description = "Set a reminder.") +public class SetSubCommand extends BatSubCommand { + public SetSubCommand() { + super.addOption(OptionType.STRING, "reminder", "The reminder to set.", true); + super.addOption(OptionType.STRING, "time", "After how long should the reminder be sent. (eg: 5m)", true); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + ReminderProfile profile = guild.getReminderProfile(); + if (profile.getReminderCount(user.getDiscordUser()) >= ReminderFeature.MAX_REMINDERS) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You have reached the maximum amount of reminders.") + .build()).queue(); + return; + } + + OptionMapping reminderOption = event.getOption("reminder"); + if (reminderOption == null) { + return; + } + OptionMapping timeOption = event.getOption("time"); + if (timeOption == null) { + return; + } + + String reminderText = reminderOption.getAsString(); + long time = TimeUtils.fromString(timeOption.getAsString()); + if (time == 0) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("Invalid time format.") + .build()).queue(); + return; + } + if (time < TimeUnit.MINUTES.toMillis(1)) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("The time must be at least 1 minute.") + .build()).queue(); + return; + } + if (time > ReminderFeature.MAX_REMINDER_LENGTH) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("The time must be at most %s.".formatted(TimeUtils.format(ReminderFeature.MAX_REMINDER_LENGTH))) + .build()).queue(); + return; + } + Reminder reminder = profile.addReminder(user.getDiscordUser(), event.getChannel().asTextChannel(), reminderText, new Date(System.currentTimeMillis() + time)); + + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription("Reminder for `%s` set, you will be reminded in ".formatted(reminderText, + reminder.getEndDate().toInstant().getEpochSecond())) + .build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/spotify/command/CurrentSubCommand.java b/src/main/java/cc/fascinated/bat/features/spotify/command/CurrentSubCommand.java index f9267d9..69518a2 100644 --- a/src/main/java/cc/fascinated/bat/features/spotify/command/CurrentSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/spotify/command/CurrentSubCommand.java @@ -22,6 +22,7 @@ import net.dv8tion.jda.api.interactions.components.buttons.Button; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.concurrent.TimeUnit; /** @@ -40,7 +41,9 @@ public class CurrentSubCommand extends BatSubCommand implements EventListener { @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { - event.replyEmbeds(SpotifyFeature.currentSong(spotifyService, user).build()).addComponents(createActions()).queue(); + event.replyEmbeds(SpotifyFeature.currentSong(spotifyService, user).build()).addComponents(createActions()).queue(message -> { + message.editOriginalComponents(new ArrayList<>()).queueAfter(5, TimeUnit.MINUTES); // Remove the buttons after 5 minutes + }); } @Override @SneakyThrows diff --git a/src/main/java/cc/fascinated/bat/model/BatGuild.java b/src/main/java/cc/fascinated/bat/model/BatGuild.java index f3f7726..26ebe8f 100644 --- a/src/main/java/cc/fascinated/bat/model/BatGuild.java +++ b/src/main/java/cc/fascinated/bat/model/BatGuild.java @@ -7,6 +7,7 @@ import cc.fascinated.bat.features.base.profile.FeatureProfile; import cc.fascinated.bat.features.birthday.profile.BirthdayProfile; import cc.fascinated.bat.features.logging.LogProfile; import cc.fascinated.bat.features.namehistory.profile.guild.NameHistoryProfile; +import cc.fascinated.bat.features.reminder.ReminderProfile; import cc.fascinated.bat.premium.PremiumProfile; import cc.fascinated.bat.service.DiscordService; import cc.fascinated.bat.service.MongoService; @@ -119,6 +120,15 @@ public class BatGuild extends ProfileHolder { return getProfile(LogProfile.class); } + /** + * Gets the reminder profile + * + * @return the reminder profile + */ + public ReminderProfile getReminderProfile() { + return getProfile(ReminderProfile.class); + } + /** * Saves the user */ From 35596b720b61f1e38505afeea7d80f4e083b4ac5 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:14:00 +0100 Subject: [PATCH 02/33] maybe fix a NPE?? --- src/main/java/cc/fascinated/bat/model/BatUser.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/model/BatUser.java b/src/main/java/cc/fascinated/bat/model/BatUser.java index 7acf7c4..9ae3118 100644 --- a/src/main/java/cc/fascinated/bat/model/BatUser.java +++ b/src/main/java/cc/fascinated/bat/model/BatUser.java @@ -53,6 +53,11 @@ public class BatUser extends ProfileHolder { */ private Date createdAt; + /** + * The discord user associated with this user + */ + private User user; + public BatUser(@NonNull String id, @NonNull org.bson.Document document) { this.id = id; this.document = document; @@ -61,6 +66,7 @@ public class BatUser extends ProfileHolder { User user = DiscordService.JDA.getUserById(id); if (user != null) { + this.user = user; this.globalName = user.getGlobalName(); } } @@ -78,7 +84,10 @@ public class BatUser extends ProfileHolder { * @return the guild */ public User getDiscordUser() { - return DiscordService.JDA.getUserById(id); + if (user == null) { + user = DiscordService.JDA.getUserById(id); + } + return user; } /** From ac499898e365534fea47604d0b6e52f177582bce Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:23:46 +0100 Subject: [PATCH 03/33] fix --- .../cc/fascinated/bat/config/MongoConfig.java | 23 ------------------- .../cc/fascinated/bat/model/BatGuild.java | 1 - .../java/cc/fascinated/bat/model/BatUser.java | 1 - 3 files changed, 25 deletions(-) delete mode 100644 src/main/java/cc/fascinated/bat/config/MongoConfig.java diff --git a/src/main/java/cc/fascinated/bat/config/MongoConfig.java b/src/main/java/cc/fascinated/bat/config/MongoConfig.java deleted file mode 100644 index d9f7d5c..0000000 --- a/src/main/java/cc/fascinated/bat/config/MongoConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package cc.fascinated.bat.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.mongodb.MongoDatabaseFactory; -import org.springframework.data.mongodb.core.convert.DbRefResolver; -import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; -import org.springframework.data.mongodb.core.convert.MappingMongoConverter; -import org.springframework.data.mongodb.core.mapping.MongoMappingContext; - -/** - * @author Fascinated (fascinated7) - */ -@Configuration -public class MongoConfig { - @Bean - public MappingMongoConverter mongoConverter(MongoDatabaseFactory mongoFactory, MongoMappingContext mongoMappingContext) { - DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoFactory); - MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mongoMappingContext); - mongoConverter.setMapKeyDotReplacement("-DOT"); - return mongoConverter; - } -} \ No newline at end of file diff --git a/src/main/java/cc/fascinated/bat/model/BatGuild.java b/src/main/java/cc/fascinated/bat/model/BatGuild.java index 26ebe8f..e361aa8 100644 --- a/src/main/java/cc/fascinated/bat/model/BatGuild.java +++ b/src/main/java/cc/fascinated/bat/model/BatGuild.java @@ -30,7 +30,6 @@ import java.util.Map; */ @Getter @Setter -@Document(collection = "guilds") public class BatGuild extends ProfileHolder { private static final Logger log = LoggerFactory.getLogger(BatGuild.class); /** diff --git a/src/main/java/cc/fascinated/bat/model/BatUser.java b/src/main/java/cc/fascinated/bat/model/BatUser.java index 9ae3118..56ac724 100644 --- a/src/main/java/cc/fascinated/bat/model/BatUser.java +++ b/src/main/java/cc/fascinated/bat/model/BatUser.java @@ -28,7 +28,6 @@ import java.util.Map; @RequiredArgsConstructor @Getter @Setter -@Document(collection = "users") public class BatUser extends ProfileHolder { private static final Logger log = LoggerFactory.getLogger(BatUser.class); /** From cb35182c6a5b6bfebc74f2170278696b3635115d Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:29:50 +0100 Subject: [PATCH 04/33] update reminder message --- .../cc/fascinated/bat/features/reminder/ReminderFeature.java | 2 +- src/main/java/cc/fascinated/bat/model/BatUser.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java b/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java index 0243bd8..78ff5d6 100644 --- a/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java +++ b/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java @@ -68,7 +68,7 @@ public class ReminderFeature extends Feature { toRemove.add(reminder); TextChannel channel = reminder.getChannel(); if (channel != null) { - channel.sendMessage("Hey %s! ⏰ It's time for your reminder: %s".formatted( + channel.sendMessage("Hey %s! ⏰ It's time for your reminder: `%s`".formatted( user.getAsMention(), reminder.getReminder() )).queue(); diff --git a/src/main/java/cc/fascinated/bat/model/BatUser.java b/src/main/java/cc/fascinated/bat/model/BatUser.java index 56ac724..5739d4b 100644 --- a/src/main/java/cc/fascinated/bat/model/BatUser.java +++ b/src/main/java/cc/fascinated/bat/model/BatUser.java @@ -29,7 +29,6 @@ import java.util.Map; @Getter @Setter public class BatUser extends ProfileHolder { - private static final Logger log = LoggerFactory.getLogger(BatUser.class); /** * The document that belongs to this user */ From 821190a144b5cef2d5abe46290433bf2215ad04b Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:30:27 +0100 Subject: [PATCH 05/33] fix reminder message --- .../fascinated/bat/features/reminder/command/SetSubCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/reminder/command/SetSubCommand.java b/src/main/java/cc/fascinated/bat/features/reminder/command/SetSubCommand.java index 7fca81c..86148db 100644 --- a/src/main/java/cc/fascinated/bat/features/reminder/command/SetSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/reminder/command/SetSubCommand.java @@ -73,7 +73,7 @@ public class SetSubCommand extends BatSubCommand { Reminder reminder = profile.addReminder(user.getDiscordUser(), event.getChannel().asTextChannel(), reminderText, new Date(System.currentTimeMillis() + time)); event.replyEmbeds(EmbedUtils.successEmbed() - .setDescription("Reminder for `%s` set, you will be reminded in ".formatted(reminderText, + .setDescription("Reminder for `%s` set, you will be reminded ".formatted(reminderText, reminder.getEndDate().toInstant().getEpochSecond())) .build()).queue(); } From 162d7af46b6b916309b539a5dbf5aaef358c6891 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:32:14 +0100 Subject: [PATCH 06/33] fix max reminder length --- .../cc/fascinated/bat/features/reminder/ReminderFeature.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java b/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java index 78ff5d6..aaa0467 100644 --- a/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java +++ b/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java @@ -31,7 +31,7 @@ import java.util.concurrent.TimeUnit; @DependsOn("discordService") public class ReminderFeature extends Feature { public static final int MAX_REMINDERS = 5; // 5 reminders - public static final long MAX_REMINDER_LENGTH = TimeUnit.DAYS.toMicros(7); // 7 days + public static final long MAX_REMINDER_LENGTH = TimeUnit.DAYS.toMillis(7); // 7 days private final GuildService guildService; From e795d542b9b3d0f61460f27e7ea8e9294d0591fc Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:33:07 +0100 Subject: [PATCH 07/33] update max reminder time --- .../cc/fascinated/bat/features/reminder/ReminderFeature.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java b/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java index aaa0467..2bf7129 100644 --- a/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java +++ b/src/main/java/cc/fascinated/bat/features/reminder/ReminderFeature.java @@ -31,7 +31,7 @@ import java.util.concurrent.TimeUnit; @DependsOn("discordService") public class ReminderFeature extends Feature { public static final int MAX_REMINDERS = 5; // 5 reminders - public static final long MAX_REMINDER_LENGTH = TimeUnit.DAYS.toMillis(7); // 7 days + public static final long MAX_REMINDER_LENGTH = TimeUnit.DAYS.toMillis(30); // 1 month private final GuildService guildService; From 82a87c79b24d3940320a5853d9be3d22f05d6a39 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:34:10 +0100 Subject: [PATCH 08/33] add execution time for commands --- src/main/java/cc/fascinated/bat/service/CommandService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/service/CommandService.java b/src/main/java/cc/fascinated/bat/service/CommandService.java index a7f4f46..2f621d6 100644 --- a/src/main/java/cc/fascinated/bat/service/CommandService.java +++ b/src/main/java/cc/fascinated/bat/service/CommandService.java @@ -138,6 +138,7 @@ public class CommandService extends ListenerAdapter { @Override public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { + long before = System.currentTimeMillis(); Guild discordGuild = event.getGuild(); if (event.getUser().isBot()) { return; @@ -230,7 +231,8 @@ public class CommandService extends ListenerAdapter { } } - log.info("Executing command \"{}\" for user \"{}\"", commandName, user.getDiscordUser().getName()); + log.info("Executing command \"{}\" for user \"{}\" (took: {}ms}", commandName, user.getDiscordUser().getName(), + System.currentTimeMillis() - before); executor.execute(guild, user, ranInsideGuild ? event.getChannel().asTextChannel() : event.getChannel().asPrivateChannel(), event.getMember(), event.getInteraction()); } catch (Exception ex) { From 6202aa6691a3712e3735eb8a07e5d8b5d4bc932a Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:35:58 +0100 Subject: [PATCH 09/33] update member join log --- .../bat/features/logging/listeners/MemberListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java index 0522791..3fc8d79 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java @@ -52,7 +52,7 @@ public class MemberListener implements EventListener { .setDescription(new EmbedDescriptionBuilder("Member Joined") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) .appendLine("Username: %s".formatted(user.getDiscordUser().getName()), true) - .appendLine("Account Age: ".formatted(user.getDiscordUser().getTimeCreated().toEpochSecond()), true) + .appendLine("Joined Discord: ".formatted(user.getDiscordUser().getTimeCreated().toEpochSecond()), true) .build()) .setThumbnail(user.getDiscordUser().getEffectiveAvatarUrl()) .build()); From da06a010974f9f4fe28820785eb3cdedf0ca5253 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:39:20 +0100 Subject: [PATCH 10/33] fix WebRequest#getAsEntity --- .../cc/fascinated/bat/common/WebRequest.java | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/common/WebRequest.java b/src/main/java/cc/fascinated/bat/common/WebRequest.java index 5ff5841..d316e78 100644 --- a/src/main/java/cc/fascinated/bat/common/WebRequest.java +++ b/src/main/java/cc/fascinated/bat/common/WebRequest.java @@ -31,20 +31,26 @@ public class WebRequest { * @return the response */ public static T getAsEntity(String url, Class clazz) throws RateLimitException { - ResponseEntity responseEntity = CLIENT.get() - .uri(url) - .retrieve() - .onStatus(HttpStatusCode::isError, (request, response) -> { - }) // Don't throw exceptions on error - .toEntity(clazz); + try { + ResponseEntity responseEntity = CLIENT.get() + .uri(url) + .retrieve() + .onStatus(HttpStatusCode::isError, (request, response) -> { + }) // Don't throw exceptions on error + .toEntity(clazz); - if (responseEntity.getStatusCode().isError()) { + if (responseEntity.getStatusCode().isError()) { + return null; + } + if (responseEntity.getStatusCode().isSameCodeAs(HttpStatus.TOO_MANY_REQUESTS)) { + throw new RateLimitException("Rate limit reached"); + } + return responseEntity.getBody(); + } catch (RateLimitException e) { + throw e; + } catch (Exception e) { return null; } - if (responseEntity.getStatusCode().isSameCodeAs(HttpStatus.TOO_MANY_REQUESTS)) { - throw new RateLimitException("Rate limit reached"); - } - return responseEntity.getBody(); } /** From 295d673d06ae7d089da563757a58d3e10b65529b Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:40:50 +0100 Subject: [PATCH 11/33] fix cmd execution log --- src/main/java/cc/fascinated/bat/service/CommandService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/service/CommandService.java b/src/main/java/cc/fascinated/bat/service/CommandService.java index 2f621d6..8d34305 100644 --- a/src/main/java/cc/fascinated/bat/service/CommandService.java +++ b/src/main/java/cc/fascinated/bat/service/CommandService.java @@ -231,7 +231,7 @@ public class CommandService extends ListenerAdapter { } } - log.info("Executing command \"{}\" for user \"{}\" (took: {}ms}", commandName, user.getDiscordUser().getName(), + log.info("Executing command \"{}\" for user \"{}\" (took: {}ms)", commandName, user.getDiscordUser().getName(), System.currentTimeMillis() - before); executor.execute(guild, user, ranInsideGuild ? event.getChannel().asTextChannel() : event.getChannel().asPrivateChannel(), event.getMember(), event.getInteraction()); From d7916ad24a69b57ef54185d0c1864381e08ca75d Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 00:41:28 +0100 Subject: [PATCH 12/33] oopsie, log after command was ran --- src/main/java/cc/fascinated/bat/service/CommandService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/service/CommandService.java b/src/main/java/cc/fascinated/bat/service/CommandService.java index 8d34305..5a0db14 100644 --- a/src/main/java/cc/fascinated/bat/service/CommandService.java +++ b/src/main/java/cc/fascinated/bat/service/CommandService.java @@ -231,10 +231,10 @@ public class CommandService extends ListenerAdapter { } } - log.info("Executing command \"{}\" for user \"{}\" (took: {}ms)", commandName, user.getDiscordUser().getName(), - System.currentTimeMillis() - before); executor.execute(guild, user, ranInsideGuild ? event.getChannel().asTextChannel() : event.getChannel().asPrivateChannel(), event.getMember(), event.getInteraction()); + log.info("Executed command \"{}\" for user \"{}\" (took: {}ms)", commandName, user.getDiscordUser().getName(), + System.currentTimeMillis() - before); } catch (Exception ex) { log.error("An error occurred while executing command \"{}\"", commandName, ex); event.replyEmbeds(EmbedUtils.errorEmbed() From 83250d2c0893f2545a092686d363c9f0e58d2287 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 01:59:53 +0100 Subject: [PATCH 13/33] add check to see if the member is in the guild before logging some events --- .../bat/features/logging/listeners/MemberListener.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java index 3fc8d79..2000794 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java @@ -89,6 +89,7 @@ public class MemberListener implements EventListener { for (Guild guild : DiscordService.JDA.getGuilds()) { BatGuild batGuild = guildService.getGuild(guild.getId()); if (batGuild == null) continue; + if (!guild.isMember(user.getDiscordUser())) continue; // User is not in the guild logFeature.sendLog(batGuild, LogType.MEMBER_GLOBAL_NAME_UPDATE, EmbedUtils.genericEmbed() .setDescription(new EmbedDescriptionBuilder("Member Name Updated") @@ -106,6 +107,7 @@ public class MemberListener implements EventListener { for (Guild guild : DiscordService.JDA.getGuilds()) { BatGuild batGuild = guildService.getGuild(guild.getId()); if (batGuild == null) continue; + if (!guild.isMember(user.getDiscordUser())) continue; // User is not in the guild logFeature.sendLog(batGuild, LogType.MEMBER_USERNAME_UPDATE, EmbedUtils.genericEmbed() .setDescription(new EmbedDescriptionBuilder("Member Username Updated") @@ -123,6 +125,7 @@ public class MemberListener implements EventListener { for (Guild guild : DiscordService.JDA.getGuilds()) { BatGuild batGuild = guildService.getGuild(guild.getId()); if (batGuild == null) continue; + if (!guild.isMember(user.getDiscordUser())) continue; // User is not in the guild logFeature.sendLog(batGuild, LogType.MEMBER_USERNAME_UPDATE, EmbedUtils.genericEmbed() .setDescription(new EmbedDescriptionBuilder("Member Avatar Updated") From f30697d1a6648b4daf33dfb35bedf5af4fda2fb6 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 02:03:26 +0100 Subject: [PATCH 14/33] fix null on old avatar in logs --- .../bat/features/logging/listeners/MemberListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java index 2000794..5165117 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java @@ -130,7 +130,7 @@ public class MemberListener implements EventListener { logFeature.sendLog(batGuild, LogType.MEMBER_USERNAME_UPDATE, EmbedUtils.genericEmbed() .setDescription(new EmbedDescriptionBuilder("Member Avatar Updated") .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) - .appendLine("Old Avatar: [avatar](%s)".formatted(oldAvatarUrl), true) + .appendLine("Old Avatar: %s".formatted(oldAvatarUrl == null ? "None" : "[avatar](%s)".formatted(oldAvatarUrl)), true) .appendLine("New Avatar: [avatar](%s)".formatted(newAvatarUrl), true) .build()) .build()); From 2255b02a608c13d7d110d60cfa2fd43136f3bd66 Mon Sep 17 00:00:00 2001 From: Lee Date: Wed, 3 Jul 2024 01:09:50 +0000 Subject: [PATCH 15/33] update vote cmd --- .../bat/features/base/commands/general/VoteCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/general/VoteCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/general/VoteCommand.java index 8a4731e..bdacd14 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/general/VoteCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/general/VoteCommand.java @@ -26,7 +26,7 @@ public class VoteCommand extends BatCommand { @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Vote Links"); - description.appendLine("Vote for the bot on the following websites to support us!", true); + description.appendLine("Vote for the bot on the following websites to support us!", false); for (String link : VOTE_LINKS) { description.appendLine(link, true); } From 920755eae05a566782ff834a89933d68d0dfab66 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 16:34:52 +0100 Subject: [PATCH 16/33] maybe fix member leave?? --- .../bat/features/logging/listeners/MemberListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java index 5165117..9877afc 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java @@ -64,8 +64,8 @@ public class MemberListener implements EventListener { logFeature.sendLog(guild, LogType.MEMBER_LEAVE, EmbedUtils.errorEmbed() .setDescription(new EmbedDescriptionBuilder("Member Left") - .appendLine("Member: %s".formatted(user.getDiscordUser().getAsMention()), true) - .appendLine("Username: %s".formatted(user.getDiscordUser().getName()), true) + .appendLine("Member: <@%s>".formatted(user.getId()), true) + .appendLine("Username: %s".formatted(user.getName()), true) .build()) .build()); } From f62a022ed5f458e6e6e4b48bcefe5bf9cd590fe8 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 16:51:36 +0100 Subject: [PATCH 17/33] logging messages --- .../logging/listeners/ChannelListener.java | 4 ++++ .../logging/listeners/MemberListener.java | 17 +++++++++++++++++ .../logging/listeners/MessageListener.java | 4 ++++ .../cc/fascinated/bat/service/UserService.java | 1 - 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java index 9c1bb05..bce1d21 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java @@ -8,6 +8,7 @@ import cc.fascinated.bat.features.logging.LogFeature; import cc.fascinated.bat.features.logging.LogType; import cc.fascinated.bat.model.BatGuild; import lombok.NonNull; +import lombok.extern.log4j.Log4j2; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.unions.ChannelUnion; import net.dv8tion.jda.api.events.channel.ChannelCreateEvent; @@ -20,6 +21,7 @@ import org.springframework.stereotype.Component; * @author Fascinated (fascinated7) */ @Component +@Log4j2 public class ChannelListener implements EventListener { private final LogFeature logFeature; @@ -30,6 +32,7 @@ public class ChannelListener implements EventListener { @Override public void onChannelCreate(@NonNull BatGuild guild, @NonNull ChannelCreateEvent event) { + log.info("Channel {} was created in guild {}", event.getChannel().getName(), guild.getName()); logFeature.sendLog(guild, LogType.CHANNEL_CREATE, EmbedUtils.successEmbed() .setDescription(new EmbedDescriptionBuilder("%s Channel Created".formatted(EnumUtils.getEnumName(event.getChannel().getType()))) .appendLine("Channel: %s".formatted(event.getChannel().getAsMention()), true) @@ -40,6 +43,7 @@ public class ChannelListener implements EventListener { @Override public void onChannelDelete(@NonNull BatGuild guild, @NonNull ChannelDeleteEvent event) { + log.info("Channel {} was deleted in guild {}", event.getChannel().getName(), guild.getName()); ChannelUnion channel = event.getChannel(); EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("%s Channel Deleted".formatted(EnumUtils.getEnumName(channel.getType()))) .appendLine("Name: #%s".formatted(channel.getName()), true); diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java index 9877afc..fbfd20b 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java @@ -23,6 +23,8 @@ import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateTimeOutEv import net.dv8tion.jda.api.events.user.update.UserUpdateAvatarEvent; import net.dv8tion.jda.api.events.user.update.UserUpdateGlobalNameEvent; import net.dv8tion.jda.api.events.user.update.UserUpdateNameEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @@ -35,6 +37,7 @@ import java.util.List; */ @Component public class MemberListener implements EventListener { + private static final Logger log = LoggerFactory.getLogger(MemberListener.class); private final LogFeature logFeature; private final GuildService guildService; @@ -47,6 +50,7 @@ public class MemberListener implements EventListener { @Override public void onGuildMemberJoin(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberJoinEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" joined the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_JOIN, EmbedUtils.successEmbed() .setDescription(new EmbedDescriptionBuilder("Member Joined") @@ -61,6 +65,7 @@ public class MemberListener implements EventListener { @Override public void onGuildMemberLeave(@NonNull BatGuild guild, BatUser user, @NonNull GuildMemberRemoveEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" left the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_LEAVE, EmbedUtils.errorEmbed() .setDescription(new EmbedDescriptionBuilder("Member Left") @@ -73,6 +78,7 @@ public class MemberListener implements EventListener { @Override public void onGuildMemberUpdateNickname(@NonNull BatGuild guild, @NonNull BatUser user, String oldName, String newName, @NonNull GuildMemberUpdateNicknameEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" changed their nickname from \"{}\" to \"{}\" in the guild \"{}\"", user.getName(), oldName, newName, guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_NICKNAME_UPDATE, EmbedUtils.genericEmbed() .setDescription(new EmbedDescriptionBuilder("Member Nickname Updated") @@ -86,6 +92,8 @@ public class MemberListener implements EventListener { @Override public void onUserUpdateGlobalName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateGlobalNameEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" changed their global name from \"{}\" to \"{}\"", user.getName(), oldName, newName); + for (Guild guild : DiscordService.JDA.getGuilds()) { BatGuild batGuild = guildService.getGuild(guild.getId()); if (batGuild == null) continue; @@ -104,6 +112,8 @@ public class MemberListener implements EventListener { @Override public void onUserUpdateName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateNameEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" changed their username from \"{}\" to \"{}\"", user.getName(), oldName, newName); + for (Guild guild : DiscordService.JDA.getGuilds()) { BatGuild batGuild = guildService.getGuild(guild.getId()); if (batGuild == null) continue; @@ -122,6 +132,8 @@ public class MemberListener implements EventListener { @Override public void onUserUpdateAvatar(@NonNull BatUser user, String oldAvatarUrl, String newAvatarUrl, @NonNull UserUpdateAvatarEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" changed their avatar to \"{}\"", user.getName(), newAvatarUrl); + for (Guild guild : DiscordService.JDA.getGuilds()) { BatGuild batGuild = guildService.getGuild(guild.getId()); if (batGuild == null) continue; @@ -140,6 +152,7 @@ public class MemberListener implements EventListener { @Override public void onGuildMemberRoleAdd(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull List rolesAdded, @NonNull GuildMemberRoleAddEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" was given {} roles in the guild \"{}\"", user.getName(), rolesAdded.size(), guild.getDiscordGuild().getName()); StringBuilder roles = new StringBuilder(); for (Role role : rolesAdded) { @@ -158,6 +171,7 @@ public class MemberListener implements EventListener { @Override public void onGuildMemberRoleRemove(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull List rolesAdded, @NonNull GuildMemberRoleRemoveEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" had {} roles removed in the guild \"{}\"", user.getName(), rolesAdded.size(), guild.getDiscordGuild().getName()); StringBuilder roles = new StringBuilder(); for (Role role : rolesAdded) { @@ -176,6 +190,7 @@ public class MemberListener implements EventListener { @Override public void onGuildMemberBan(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildBanEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" was banned from the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_BAN, EmbedUtils.errorEmbed() .setDescription(new EmbedDescriptionBuilder("Member Banned") @@ -187,6 +202,7 @@ public class MemberListener implements EventListener { @Override public void onGuildMemberUnban(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildUnbanEvent event) { if (user.getDiscordUser().isBot()) return; + log.info("User \"{}\" was unbanned from the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_UNBAN, EmbedUtils.successEmbed() .setDescription(new EmbedDescriptionBuilder("Member Unbanned") @@ -199,6 +215,7 @@ public class MemberListener implements EventListener { public void onGuildMemberTimeout(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberUpdateTimeOutEvent event) { OffsetDateTime timeoutEnd = event.getNewTimeOutEnd(); if (user.getDiscordUser().isBot() || timeoutEnd == null) return; + log.info("User \"{}\" was timed out until \"{}\"", user.getName(), timeoutEnd); long seconds = timeoutEnd.toInstant().getEpochSecond(); logFeature.sendLog(guild, LogType.MEMBER_TIMEOUT, EmbedUtils.errorEmbed() diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java index b8cdbe4..f305282 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java @@ -9,6 +9,7 @@ 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.message.MessageDeleteEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; import org.springframework.beans.factory.annotation.Autowired; @@ -19,6 +20,7 @@ import org.springframework.stereotype.Component; * @author Fascinated (fascinated7) */ @Component +@Log4j2 public class MessageListener implements EventListener { private final LogFeature logFeature; @@ -30,6 +32,7 @@ public class MessageListener implements EventListener { @Override public void onGuildMessageDelete(@NonNull BatGuild guild, BatUser user, DiscordMessage message, @NonNull MessageDeleteEvent event) { if (user.getDiscordUser().isBot() || message.getAuthor().isBot()) return; + log.info("User {} deleted a message in guild {}", user.getDiscordUser().getGlobalName(), guild.getName()); logFeature.sendLog(guild, LogType.MESSAGE_DELETE, EmbedUtils.errorEmbed() .setDescription(new EmbedDescriptionBuilder("Message Deleted") @@ -44,6 +47,7 @@ public class MessageListener implements EventListener { public void onGuildMessageEdit(@NonNull BatGuild guild, @NonNull BatUser user, DiscordMessage oldMessage, @NonNull DiscordMessage newMessage, @NonNull MessageUpdateEvent event) { if (user.getDiscordUser().isBot() || newMessage.getAuthor().isBot() || oldMessage == null) return; + log.info("User {} edited a message in guild {}", user.getDiscordUser().getGlobalName(), guild.getName()); logFeature.sendLog(guild, LogType.MESSAGE_EDIT, EmbedUtils.genericEmbed() .setDescription(new EmbedDescriptionBuilder("Message Edited") diff --git a/src/main/java/cc/fascinated/bat/service/UserService.java b/src/main/java/cc/fascinated/bat/service/UserService.java index f31b61f..69331c6 100644 --- a/src/main/java/cc/fascinated/bat/service/UserService.java +++ b/src/main/java/cc/fascinated/bat/service/UserService.java @@ -92,7 +92,6 @@ public class UserService implements EventListener { @Override public void onUserUpdateGlobalName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateGlobalNameEvent event) { - log.info("User \"{}\" changed their name from \"{}\" to \"{}\"", user.getName(), oldName, newName); user.setGlobalName(newName); } } From e4183b48824fc145cb6ce0c7f5c45941883b83d3 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 19:49:19 +0100 Subject: [PATCH 18/33] impl welcomer feature --- .../bat/features/welcomer/WelcomerEmbed.java | 50 ++++++ .../features/welcomer/WelcomerFeature.java | 23 +++ .../features/welcomer/WelcomerListener.java | 32 ++++ .../features/welcomer/WelcomerMessage.java | 27 ++++ .../welcomer/WelcomerPlaceholders.java | 82 ++++++++++ .../features/welcomer/WelcomerProfile.java | 144 ++++++++++++++++++ .../welcomer/command/ChannelSubCommand.java | 30 ++++ .../welcomer/command/CurrentSubCommand.java | 64 ++++++++ .../welcomer/command/EmbedSubCommand.java | 96 ++++++++++++ .../welcomer/command/MessageSubCommand.java | 52 +++++++ .../welcomer/command/ResetSubCommand.java | 36 +++++ .../welcomer/command/WelcomerCommand.java | 25 +++ .../cc/fascinated/bat/model/BatGuild.java | 10 ++ 13 files changed, 671 insertions(+) create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/WelcomerEmbed.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/WelcomerFeature.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/WelcomerListener.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/WelcomerMessage.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/WelcomerPlaceholders.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/command/ChannelSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/command/CurrentSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/command/MessageSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/command/ResetSubCommand.java create mode 100644 src/main/java/cc/fascinated/bat/features/welcomer/command/WelcomerCommand.java diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerEmbed.java b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerEmbed.java new file mode 100644 index 0000000..c7197f8 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerEmbed.java @@ -0,0 +1,50 @@ +package cc.fascinated.bat.features.welcomer; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; +import net.dv8tion.jda.api.EmbedBuilder; + +/** + * @author Fascinated (fascinated7) + */ +@AllArgsConstructor +@Getter +@Setter +public class WelcomerEmbed { + /** + * The title of the embed + */ + private String title; + + /** + * The description of the embed + */ + @NonNull private String description; + + /** + * The color of the embed + */ + @NonNull private String color; + + /** + * Should we ping the user before sending the message? + */ + private boolean pingBeforeSend; + + /** + * Builds the embed and replaces the placeholders + * + * @return The built embed + */ + public EmbedBuilder buildEmbed(Object... replacements) { + EmbedBuilder embedBuilder = new EmbedBuilder(); + if (title != null) { + embedBuilder.setTitle(WelcomerPlaceholders.replaceAllPlaceholders(title, replacements)); + } + embedBuilder.setDescription(WelcomerPlaceholders.replaceAllPlaceholders(description, replacements)); + embedBuilder.setColor(Integer.parseInt(color, 16)); + return embedBuilder; + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerFeature.java b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerFeature.java new file mode 100644 index 0000000..244e468 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerFeature.java @@ -0,0 +1,23 @@ +package cc.fascinated.bat.features.welcomer; + +import cc.fascinated.bat.command.Category; +import cc.fascinated.bat.features.Feature; +import cc.fascinated.bat.features.welcomer.command.WelcomerCommand; +import cc.fascinated.bat.service.CommandService; +import lombok.NonNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +public class WelcomerFeature extends Feature { + @Autowired + public WelcomerFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) { + super("Welcomer", true,Category.SERVER); + + super.registerCommand(commandService, context.getBean(WelcomerCommand.class)); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerListener.java b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerListener.java new file mode 100644 index 0000000..b479891 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerListener.java @@ -0,0 +1,32 @@ +package cc.fascinated.bat.features.welcomer; + +import cc.fascinated.bat.event.EventListener; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import lombok.NonNull; +import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +public class WelcomerListener implements EventListener { + private final WelcomerFeature welcomerFeature; + + @Autowired + public WelcomerListener(WelcomerFeature welcomerFeature) { + this.welcomerFeature = welcomerFeature; + } + + @Override + public void onGuildMemberJoin(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberJoinEvent event) { + if (guild.getFeatureProfile().isFeatureDisabled(welcomerFeature)) { // Check if the feature is disabled + return; + } + + WelcomerProfile profile = guild.getWelcomerProfile(); + profile.sendWelcomeMessage(user); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerMessage.java b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerMessage.java new file mode 100644 index 0000000..3ad05aa --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerMessage.java @@ -0,0 +1,27 @@ +package cc.fascinated.bat.features.welcomer; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +/** + * @author Fascinated (fascinated7) + */ +@AllArgsConstructor +@Getter +@Setter +public class WelcomerMessage { + /** + * The message to send + */ + private String message; + + /** + * Builds the message and replaces the placeholders + * + * @return The built message + */ + public String buildMessage(Object... replacements) { + return WelcomerPlaceholders.replaceAllPlaceholders(message, replacements); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerPlaceholders.java b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerPlaceholders.java new file mode 100644 index 0000000..202242e --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerPlaceholders.java @@ -0,0 +1,82 @@ +package cc.fascinated.bat.features.welcomer; + +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Date; + +/** + * @author Fascinated (fascinated7) + */ +@AllArgsConstructor +@Getter +public enum WelcomerPlaceholders { + USER_MENTION("{user_mention}", BatUser.class) { + @Override + public String replacePlaceholder(Object object) { + return ((BatUser) object).getDiscordUser().getAsMention(); + } + }, + USER_NAME("{user_name}", BatUser.class) { + @Override + public String replacePlaceholder(Object object) { + return ((BatUser) object).getName(); + } + }, + GUILD_NAME("{guild_name}", BatGuild.class) { + @Override + public String replacePlaceholder(Object object) { + return ((BatGuild) object).getName(); + } + }, + JOIN_DATE("{join_date}", null) { + @Override + public String replacePlaceholder(Object object) { + return "".formatted(new Date().toInstant().getEpochSecond()); + } + }; + + /** + * The placeholder string that will get replaced + */ + private final String placeholder; + + /** + * The class that the placeholder is associated with + */ + private final Class clazz; + + /** + * Replaces the placeholder with the string based on the overridden method + * + * @param object The object to replace the placeholder with + * @return The string with the placeholder replaced + */ + public String replacePlaceholder(Object object) { + if (clazz != null && !clazz.isInstance(object)) { + throw new IllegalArgumentException("Object is not an instance of " + clazz.getName()); + } + return null; + } + + /** + * Replaces all placeholders in a message with the objects provided + * + * @param message The message to replace the placeholders in + * @param objects The objects to replace the placeholders with + * @return The message with the placeholders replaced + */ + public static String replaceAllPlaceholders(String message, Object... objects) { + for (WelcomerPlaceholders placeholder : values()) { + for (Object object : objects) { + if (placeholder.getClazz() != null && !placeholder.getClazz().isInstance(object)) { + continue; + } + message = message.replace(placeholder.getPlaceholder(), placeholder.replacePlaceholder(object)); + } + } + return message; + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java new file mode 100644 index 0000000..bccc48b --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java @@ -0,0 +1,144 @@ +package cc.fascinated.bat.features.welcomer; + +import cc.fascinated.bat.common.Serializable; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.service.DiscordService; +import com.google.gson.Gson; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import org.bson.Document; + +/** + * @author Fascinated (fascinated7) + */ +@Getter @Setter +public class WelcomerProfile extends Serializable { + /** + * The welcomer message, null if we're using an embed + */ + private WelcomerMessage welcomerMessage; + + /** + * The welcomer embed, null if we're using a message + */ + private WelcomerEmbed welcomerEmbed; + + /** + * The channel to send the welcomer messages to + */ + private TextChannel channel; + + /** + * Gets the welcomer message + * + * @return The welcomer message, false if we're using an embed + */ + public boolean isEmbed() { + return welcomerEmbed != null; + } + + /** + * Gets the welcomer message + * + * @return The welcomer message, false if we're using an embed + */ + public boolean isMessage() { + return welcomerMessage != null; + } + + /** + * Sets the welcomer message + *

+ * This will disable the embed if it's enabled + *

+ */ + public void setMessage(String message) { + welcomerMessage = new WelcomerMessage(message); + welcomerEmbed = null; + } + + /** + * Sets the welcomer embed + *

+ * This will disable the message if it's enabled + *

+ */ + public void setEmbed(String title, String description, String color, boolean pingBeforeSend) { + welcomerEmbed = new WelcomerEmbed(title, description, color, pingBeforeSend); + welcomerMessage = null; + } + + /** + * Sends the welcome message to the user + * + * @param user The user to send the message to + */ + public void sendWelcomeMessage(BatUser user) { + if (this.channel == null || (!this.isMessage() && !this.isEmbed())) { + return; + } + if (welcomerEmbed != null) { + if (welcomerEmbed.isPingBeforeSend()) { // Ping the user before sending the message + this.channel.sendMessage(user.getDiscordUser().getAsMention()).queue(); + } + this.channel.sendMessageEmbeds(welcomerEmbed.buildEmbed(user).build()).queue(); + return; + } + if (welcomerMessage != null) { + this.channel.sendMessage(welcomerMessage.buildMessage(user)).queue(); + } + } + + @Override + public void load(Document document, Gson gson) { + Document welcomerMessageDocument = document.get("welcomerMessage", Document.class); + if (welcomerMessageDocument != null) { + welcomerMessage = new WelcomerMessage( + welcomerMessageDocument.getString("message") + ); + } + Document welcomerEmbedDocument = document.get("welcomerEmbed", Document.class); + if (welcomerEmbedDocument != null) { + welcomerEmbed = new WelcomerEmbed( + welcomerEmbedDocument.getString("title"), + welcomerEmbedDocument.getString("description"), + welcomerEmbedDocument.getString("color"), + welcomerEmbedDocument.getBoolean("pingBeforeSend") + ); + } + String channelId = document.getString("channelId"); + if (channelId != null) { + TextChannel textChannel = DiscordService.JDA.getTextChannelById(channelId); + if (textChannel != null) { + channel = textChannel; + } + } + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + if (welcomerMessage != null) { + document.put("welcomerMessage", new Document("message", welcomerMessage.getMessage())); + } + if (welcomerEmbed != null) { + document.put("welcomerEmbed", new Document() + .append("title", welcomerEmbed.getTitle()) + .append("description", welcomerEmbed.getDescription()) + .append("color", welcomerEmbed.getColor()) + .append("pingBeforeSend", welcomerEmbed.isPingBeforeSend()) + ); + } + if (channel != null) { + document.put("channelId", channel.getIdLong()); + } + return document; + } + + @Override + public void reset() { + welcomerMessage = null; + welcomerEmbed = null; + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/ChannelSubCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/ChannelSubCommand.java new file mode 100644 index 0000000..d065a34 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/ChannelSubCommand.java @@ -0,0 +1,30 @@ +package cc.fascinated.bat.features.welcomer.command; + +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.welcomer.WelcomerProfile; +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.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("welcomer:channel.sub") +@CommandInfo(name = "channel", description = "Set the welcomer channel") +public class ChannelSubCommand extends BatSubCommand { + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + WelcomerProfile profile = guild.getWelcomerProfile(); + profile.setChannel(guild.getDiscordGuild().getTextChannelById(channel.getId())); + + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription("The welcomer channel has been set to %s".formatted(channel.getAsMention())) + .build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/CurrentSubCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/CurrentSubCommand.java new file mode 100644 index 0000000..c73966b --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/CurrentSubCommand.java @@ -0,0 +1,64 @@ +package cc.fascinated.bat.features.welcomer.command; + +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.welcomer.WelcomerPlaceholders; +import cc.fascinated.bat.features.welcomer.WelcomerProfile; +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.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("welcomer:current.sub") +@CommandInfo(name = "current", description = "View the current welcomer configuration") +public class CurrentSubCommand extends BatSubCommand { + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + WelcomerProfile profile = guild.getWelcomerProfile(); + if (!profile.isEmbed() && !profile.isMessage()) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("The welcomer is not configured.\n\n" + getPlaceholders(guild, user)) + .build()).queue(); + return; + } + + if (profile.isEmbed()) { + event.replyEmbeds(profile.getWelcomerEmbed().buildEmbed(guild, user) + .appendDescription("\n\n" + getPlaceholders(guild, user)) + .build()).queue(); + return; + } + if (profile.isMessage()) { + event.replyEmbeds(EmbedUtils.genericEmbed() + .setDescription("**Preview:** %s\n*note: the real message won't be an embed*\n\n%s".formatted( + profile.getWelcomerMessage().buildMessage(guild, user), + getPlaceholders(guild, user) + )) + .build()).queue(); + } + } + + /** + * Get the placeholders that the user can use + * + * @param replacements What to replace the placeholders using + * @return The placeholders + */ + public String getPlaceholders(Object... replacements) { + StringBuilder builder = new StringBuilder(); + builder.append("**Available Placeholders:**\n"); + for (WelcomerPlaceholders placeholder : WelcomerPlaceholders.values()) { + String placeholderString = placeholder.getPlaceholder(); + builder.append("`").append(placeholderString).append("` - ") + .append(WelcomerPlaceholders.replaceAllPlaceholders(placeholderString, replacements)).append("\n"); + } + return builder.toString(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java new file mode 100644 index 0000000..3395cc8 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java @@ -0,0 +1,96 @@ +package cc.fascinated.bat.features.welcomer.command; + +import cc.fascinated.bat.Emojis; +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.welcomer.WelcomerProfile; +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.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +import java.awt.*; + +/** + * @author Fascinated (fascinated7) + */ +@Component("welcomer:embed.sub") +@CommandInfo(name = "embed", description = "Set the welcomer embed (this will remove the welcomer plain message if set)") +public class EmbedSubCommand extends BatSubCommand { + public EmbedSubCommand() { + super.addOption(OptionType.BOOLEAN, "ping-before-send", "Should we ping the user before sending the message?", true); + super.addOption(OptionType.STRING, "description", "The description of the embed", true); + super.addOption(OptionType.STRING, "color", "The color of the embed", true); + super.addOption(OptionType.STRING, "title", "The title of the embed (only set if you want a title)", false); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + WelcomerProfile profile = guild.getWelcomerProfile(); + OptionMapping titleOption = event.getOption("title"); + OptionMapping descriptionOption = event.getOption("description"); + OptionMapping colorOption = event.getOption("color"); + OptionMapping pingBeforeSendOption = event.getOption("ping-before-send"); + if (descriptionOption == null || colorOption == null || pingBeforeSendOption == null) { + return; + } + String title = titleOption == null ? null : titleOption.getAsString(); + String description = descriptionOption.getAsString(); + String color = colorOption.getAsString(); + boolean pingBeforeSend = pingBeforeSendOption.getAsBoolean(); + + // Validate the input + if (color.length() != 6 || Color.decode("#" + color).getRGB() == -1){ + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("The color must be a valid hex color code\n" + + "You can use this website to get a hex color code: https://htmlcolorcodes.com") + .build()).queue(); + return; + } + if (title != null && title.length() > 128) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("The title must be less than 128 characters") + .build()).queue(); + return; + } + if (description.length() > 512) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("The description must be less than 512 characters") + .build()).queue(); + return; + } + + color = color.replace("#", ""); // Remove # if the user added it + boolean isMessageEnabled = profile.isMessage(); + profile.setEmbed(title, description, color, pingBeforeSend); + EmbedDescriptionBuilder successDescription = new EmbedDescriptionBuilder("Welcomer Embed") + .appendLine("%s Successfully set the welcomer embed!".formatted(Emojis.CHECK_MARK_EMOJI), false); + if (isMessageEnabled) { + successDescription.appendLine("*This has removed the plain message welcomer*", false); + } + + successDescription.emptyLine(); + successDescription.appendLine("**Configuration:**", false); + if (title != null) { + successDescription.appendLine("Title: `%s`".formatted(title), true); + } + successDescription.appendLine("Description: `%s`".formatted(description), true); + successDescription.appendLine("Color: `#%s`".formatted(color), true); + successDescription.appendLine("Ping Before Send: %s".formatted(pingBeforeSend ? Emojis.CHECK_MARK_EMOJI.getFormatted() + " *(Preview won't ping you)*" : Emojis.CROSS_MARK_EMOJI), true); + successDescription.emptyLine(); + successDescription.appendLine("**Preview Below:**", false); + event.replyEmbeds( + EmbedUtils.successEmbed() + .setDescription(successDescription.build()) + .build(), + profile.getWelcomerEmbed().buildEmbed(guild, user).build() + ).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/MessageSubCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/MessageSubCommand.java new file mode 100644 index 0000000..bed2f1d --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/MessageSubCommand.java @@ -0,0 +1,52 @@ +package cc.fascinated.bat.features.welcomer.command; + +import cc.fascinated.bat.Emojis; +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedDescriptionBuilder; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.welcomer.WelcomerPlaceholders; +import cc.fascinated.bat.features.welcomer.WelcomerProfile; +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.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("welcomer:message.sub") +@CommandInfo(name = "message", description = "Set the welcomer message (this will remove the welcomer embed if set)") +public class MessageSubCommand extends BatSubCommand { + public MessageSubCommand() { + super.addOption(OptionType.STRING, "message", "The message to send", true); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + WelcomerProfile profile = guild.getWelcomerProfile(); + OptionMapping messageOption = event.getOption("message"); + if (messageOption == null) { + return; + } + String message = messageOption.getAsString(); + boolean isEmbedEnabled = profile.isEmbed(); + profile.setMessage(message); + + EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("Welcomer Message") + .appendLine("%s Set the message to `%s`".formatted(Emojis.CHECK_MARK_EMOJI, message), false); + if (isEmbedEnabled) { + description.appendLine("*This has removed the embed welcomer*", false); + } + description.emptyLine(); + description.appendLine("**Preview:** %s".formatted(WelcomerPlaceholders.replaceAllPlaceholders(message, guild, user)), false); + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription(description.build()) + .build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/ResetSubCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/ResetSubCommand.java new file mode 100644 index 0000000..372fc08 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/ResetSubCommand.java @@ -0,0 +1,36 @@ +package cc.fascinated.bat.features.welcomer.command; + +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.welcomer.WelcomerProfile; +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.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("welcomer:reset.sub") +@CommandInfo(name = "reset", description = "Clear the welcomer configuration") +public class ResetSubCommand extends BatSubCommand { + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + WelcomerProfile profile = guild.getWelcomerProfile(); + if (!profile.isEmbed() && !profile.isMessage()) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("The welcomer is not configured") + .build()).queue(); + return; + } + + profile.reset(); + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription("The welcomer configuration has been reset") + .build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/WelcomerCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/WelcomerCommand.java new file mode 100644 index 0000000..c0dfc7a --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/WelcomerCommand.java @@ -0,0 +1,25 @@ +package cc.fascinated.bat.features.welcomer.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo(name = "welcomer", description = "Configure the welcomer on your server", requiredPermissions = Permission.MANAGE_SERVER) +public class WelcomerCommand extends BatCommand { + @Autowired + public WelcomerCommand(@NonNull ApplicationContext context) { + super.addSubCommand(context.getBean(MessageSubCommand.class)); + super.addSubCommand(context.getBean(EmbedSubCommand.class)); + super.addSubCommand(context.getBean(CurrentSubCommand.class)); + super.addSubCommand(context.getBean(ChannelSubCommand.class)); + super.addSubCommand(context.getBean(ResetSubCommand.class)); + } +} diff --git a/src/main/java/cc/fascinated/bat/model/BatGuild.java b/src/main/java/cc/fascinated/bat/model/BatGuild.java index e361aa8..e00d483 100644 --- a/src/main/java/cc/fascinated/bat/model/BatGuild.java +++ b/src/main/java/cc/fascinated/bat/model/BatGuild.java @@ -8,6 +8,7 @@ import cc.fascinated.bat.features.birthday.profile.BirthdayProfile; import cc.fascinated.bat.features.logging.LogProfile; import cc.fascinated.bat.features.namehistory.profile.guild.NameHistoryProfile; import cc.fascinated.bat.features.reminder.ReminderProfile; +import cc.fascinated.bat.features.welcomer.WelcomerProfile; import cc.fascinated.bat.premium.PremiumProfile; import cc.fascinated.bat.service.DiscordService; import cc.fascinated.bat.service.MongoService; @@ -128,6 +129,15 @@ public class BatGuild extends ProfileHolder { return getProfile(ReminderProfile.class); } + /** + * Gets the welcomer profile + * + * @return the welcomer profile + */ + public WelcomerProfile getWelcomerProfile() { + return getProfile(WelcomerProfile.class); + } + /** * Saves the user */ From 90aaf5422f7ef8520f94f3d3461dbcd27ecd7dc5 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 19:53:47 +0100 Subject: [PATCH 19/33] fix some messages --- .../bat/features/logging/listeners/ChannelListener.java | 4 ++-- .../bat/features/logging/listeners/MessageListener.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java index bce1d21..0e014f5 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java @@ -32,7 +32,7 @@ public class ChannelListener implements EventListener { @Override public void onChannelCreate(@NonNull BatGuild guild, @NonNull ChannelCreateEvent event) { - log.info("Channel {} was created in guild {}", event.getChannel().getName(), guild.getName()); + log.info("Channel \"{}\" was created in guild \"{}\"", event.getChannel().getName(), guild.getName()); logFeature.sendLog(guild, LogType.CHANNEL_CREATE, EmbedUtils.successEmbed() .setDescription(new EmbedDescriptionBuilder("%s Channel Created".formatted(EnumUtils.getEnumName(event.getChannel().getType()))) .appendLine("Channel: %s".formatted(event.getChannel().getAsMention()), true) @@ -43,7 +43,7 @@ public class ChannelListener implements EventListener { @Override public void onChannelDelete(@NonNull BatGuild guild, @NonNull ChannelDeleteEvent event) { - log.info("Channel {} was deleted in guild {}", event.getChannel().getName(), guild.getName()); + log.info("Channel \"{}\" was deleted in guild \"{}\"", event.getChannel().getName(), guild.getName()); ChannelUnion channel = event.getChannel(); EmbedDescriptionBuilder description = new EmbedDescriptionBuilder("%s Channel Deleted".formatted(EnumUtils.getEnumName(channel.getType()))) .appendLine("Name: #%s".formatted(channel.getName()), true); diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java index f305282..7f8ec22 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java @@ -32,7 +32,7 @@ public class MessageListener implements EventListener { @Override public void onGuildMessageDelete(@NonNull BatGuild guild, BatUser user, DiscordMessage message, @NonNull MessageDeleteEvent event) { if (user.getDiscordUser().isBot() || message.getAuthor().isBot()) return; - log.info("User {} deleted a message in guild {}", user.getDiscordUser().getGlobalName(), guild.getName()); + log.info("User \"{}\" deleted a message in guild \"{}\"", user.getDiscordUser().getGlobalName(), guild.getName()); logFeature.sendLog(guild, LogType.MESSAGE_DELETE, EmbedUtils.errorEmbed() .setDescription(new EmbedDescriptionBuilder("Message Deleted") @@ -47,7 +47,7 @@ public class MessageListener implements EventListener { public void onGuildMessageEdit(@NonNull BatGuild guild, @NonNull BatUser user, DiscordMessage oldMessage, @NonNull DiscordMessage newMessage, @NonNull MessageUpdateEvent event) { if (user.getDiscordUser().isBot() || newMessage.getAuthor().isBot() || oldMessage == null) return; - log.info("User {} edited a message in guild {}", user.getDiscordUser().getGlobalName(), guild.getName()); + log.info("User \"{}\" edited a message in guild \"{}\"", user.getDiscordUser().getGlobalName(), guild.getName()); logFeature.sendLog(guild, LogType.MESSAGE_EDIT, EmbedUtils.genericEmbed() .setDescription(new EmbedDescriptionBuilder("Message Edited") From f6834db9cb0e8aec24695316819eacb4b5eec846 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 20:19:21 +0100 Subject: [PATCH 20/33] add 8ball command --- .../bat/features/base/BaseFeature.java | 2 + .../base/commands/fun/EightBallCommand.java | 62 +++++++++++++++++++ .../cc/fascinated/bat/model/BatGuild.java | 1 - .../java/cc/fascinated/bat/model/BatUser.java | 3 - 4 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 src/main/java/cc/fascinated/bat/features/base/commands/fun/EightBallCommand.java diff --git a/src/main/java/cc/fascinated/bat/features/base/BaseFeature.java b/src/main/java/cc/fascinated/bat/features/base/BaseFeature.java index 129df85..8cda4dc 100644 --- a/src/main/java/cc/fascinated/bat/features/base/BaseFeature.java +++ b/src/main/java/cc/fascinated/bat/features/base/BaseFeature.java @@ -3,6 +3,7 @@ package cc.fascinated.bat.features.base; import cc.fascinated.bat.command.Category; import cc.fascinated.bat.features.Feature; import cc.fascinated.bat.features.base.commands.botadmin.premium.PremiumAdminCommand; +import cc.fascinated.bat.features.base.commands.fun.EightBallCommand; import cc.fascinated.bat.features.base.commands.fun.image.ImageCommand; import cc.fascinated.bat.features.base.commands.general.*; import cc.fascinated.bat.features.base.commands.general.avatar.AvatarCommand; @@ -39,5 +40,6 @@ public class BaseFeature extends Feature { super.registerCommand(commandService, context.getBean(AvatarCommand.class)); super.registerCommand(commandService, context.getBean(ImageCommand.class)); super.registerCommand(commandService, context.getBean(FeatureCommand.class)); + super.registerCommand(commandService, context.getBean(EightBallCommand.class)); } } diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/fun/EightBallCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/fun/EightBallCommand.java new file mode 100644 index 0000000..52ea3e8 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/base/commands/fun/EightBallCommand.java @@ -0,0 +1,62 @@ +package cc.fascinated.bat.features.base.commands.fun; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +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.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo(name = "8ball", description = "Ask the magic 8ball a question") +public class EightBallCommand extends BatCommand { + private final String[] responses = new String[]{ + "It is certain", + "It is decidedly so", + "Without a doubt", + "Yes, definitely", + "You may rely on it", + "As I see it, yes", + "Most likely", + "Outlook good", + "Yes", + "Signs point to yes", + "Reply hazy, try again", + "Ask again later", + "Better not tell you now", + "Cannot predict now", + "Concentrate and ask again", + "Don't count on it", + "My reply is no", + "My sources say no", + "Outlook not so good", + "Very doubtful" + }; + + public EightBallCommand() { + super.addOption(OptionType.STRING, "question", "The question you want to ask the 8ball", true); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping questionOption = event.getOption("question"); + if (questionOption == null) { + return; + } + String question = questionOption.getAsString(); + String response = responses[(int) (Math.random() * responses.length)]; + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription("You asked: `%s`\n\n:8ball: The magic 8ball says: `%s`".formatted(question, response)) + .build()) + .queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/model/BatGuild.java b/src/main/java/cc/fascinated/bat/model/BatGuild.java index e00d483..fb40213 100644 --- a/src/main/java/cc/fascinated/bat/model/BatGuild.java +++ b/src/main/java/cc/fascinated/bat/model/BatGuild.java @@ -20,7 +20,6 @@ import net.dv8tion.jda.api.entities.Guild; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.mapping.Document; import java.util.Date; import java.util.HashMap; diff --git a/src/main/java/cc/fascinated/bat/model/BatUser.java b/src/main/java/cc/fascinated/bat/model/BatUser.java index 5739d4b..9e9808f 100644 --- a/src/main/java/cc/fascinated/bat/model/BatUser.java +++ b/src/main/java/cc/fascinated/bat/model/BatUser.java @@ -13,10 +13,7 @@ import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.Setter; import net.dv8tion.jda.api.entities.User; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.mapping.Document; import java.util.Date; import java.util.HashMap; From 11e7ca4aa61eeb38bbc58eff235974e4fb36a560 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 21:43:29 +0100 Subject: [PATCH 21/33] impl purge command --- .../cc/fascinated/bat/command/Category.java | 3 +- .../logging/listeners/MessageListener.java | 2 +- .../messagesnipe/MessageSnipeFeature.java | 2 +- .../moderation/ModerationFeature.java | 23 +++++++ .../moderation/command/PurgeCommand.java | 67 +++++++++++++++++++ 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/ModerationFeature.java create mode 100644 src/main/java/cc/fascinated/bat/features/moderation/command/PurgeCommand.java diff --git a/src/main/java/cc/fascinated/bat/command/Category.java b/src/main/java/cc/fascinated/bat/command/Category.java index e156033..a497c78 100644 --- a/src/main/java/cc/fascinated/bat/command/Category.java +++ b/src/main/java/cc/fascinated/bat/command/Category.java @@ -16,9 +16,10 @@ public enum Category { GENERAL(Emoji.fromUnicode("U+2699"), "General", false), FUN(Emoji.fromFormatted("U+1F973"), "Fun", false), SERVER(Emoji.fromFormatted("U+1F5A5"), "Server", false), + MODERATION(Emoji.fromFormatted("U+1F6E0"), "Moderation", false), UTILITY(Emoji.fromFormatted("U+1F6E0"), "Utility", false), MUSIC(Emoji.fromFormatted("U+1F3B5"), "Music", false), - SNIPE(Emoji.fromFormatted("U+1F4A3"), "Snipe", false), + MESSAGES(Emoji.fromFormatted("U+1F4A3"), "Snipe", false), LOGS(Emoji.fromFormatted("U+1F4D1"), "Logs", false), BEAT_SABER(Emoji.fromFormatted("U+1FA84"), "Beat Saber", false), BOT_ADMIN(null, null, true); diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java index 7f8ec22..c3c069e 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MessageListener.java @@ -31,7 +31,7 @@ public class MessageListener implements EventListener { @Override public void onGuildMessageDelete(@NonNull BatGuild guild, BatUser user, DiscordMessage message, @NonNull MessageDeleteEvent event) { - if (user.getDiscordUser().isBot() || message.getAuthor().isBot()) return; + if (user == null || user.getDiscordUser().isBot() || message.getAuthor().isBot()) return; log.info("User \"{}\" deleted a message in guild \"{}\"", user.getDiscordUser().getGlobalName(), guild.getName()); logFeature.sendLog(guild, LogType.MESSAGE_DELETE, EmbedUtils.errorEmbed() diff --git a/src/main/java/cc/fascinated/bat/features/messagesnipe/MessageSnipeFeature.java b/src/main/java/cc/fascinated/bat/features/messagesnipe/MessageSnipeFeature.java index e6f4dfd..265a6d3 100644 --- a/src/main/java/cc/fascinated/bat/features/messagesnipe/MessageSnipeFeature.java +++ b/src/main/java/cc/fascinated/bat/features/messagesnipe/MessageSnipeFeature.java @@ -30,7 +30,7 @@ public class MessageSnipeFeature extends Feature implements EventListener { @Autowired public MessageSnipeFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) { - super("Message Snipe", false, Category.SNIPE); + super("Message Snipe", false, Category.MESSAGES); super.registerCommand(commandService, context.getBean(MessageSnipeCommand.class)); } diff --git a/src/main/java/cc/fascinated/bat/features/moderation/ModerationFeature.java b/src/main/java/cc/fascinated/bat/features/moderation/ModerationFeature.java new file mode 100644 index 0000000..a632182 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/ModerationFeature.java @@ -0,0 +1,23 @@ +package cc.fascinated.bat.features.moderation; + +import cc.fascinated.bat.command.Category; +import cc.fascinated.bat.features.Feature; +import cc.fascinated.bat.features.moderation.command.PurgeCommand; +import cc.fascinated.bat.service.CommandService; +import lombok.NonNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component +public class ModerationFeature extends Feature { + @Autowired + public ModerationFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService) { + super("Moderation", true,Category.MODERATION); + + super.registerCommand(commandService, context.getBean(PurgeCommand.class)); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/moderation/command/PurgeCommand.java b/src/main/java/cc/fascinated/bat/features/moderation/command/PurgeCommand.java new file mode 100644 index 0000000..3efc61b --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/moderation/command/PurgeCommand.java @@ -0,0 +1,67 @@ +package cc.fascinated.bat.features.moderation.command; + +import cc.fascinated.bat.command.BatCommand; +import cc.fascinated.bat.command.CommandInfo; +import cc.fascinated.bat.common.EmbedUtils; +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.Message; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * @author Fascinated (fascinated7) + */ +@Component +@CommandInfo(name = "purge", description = "Purge messages from a channel", requiredPermissions = Permission.MESSAGE_MANAGE) +public class PurgeCommand extends BatCommand { + private final long MESSAGE_DELETE_DELAY = TimeUnit.SECONDS.toMillis(10); + + public PurgeCommand() { + super.addOption(OptionType.INTEGER, "amount", "The amount of messages to remove", true); + } + + @Override + public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { + OptionMapping amountOption = event.getOption("amount"); + if (amountOption == null) { + return; + } + int amount = amountOption.getAsInt(); + if (amount < 2 || amount > 100) { + event.replyEmbeds(EmbedUtils.errorEmbed() + .setDescription("You can only purge between 2 and 100 messages") + .build()).queue(); + return; + } + + event.replyEmbeds(EmbedUtils.successEmbed() + .setDescription("Purging `%s` messages...".formatted(amount)) + .build()).queue(then -> { + TextChannel textChannel = (TextChannel) channel; + textChannel.getHistory().retrievePast(amount + 1).queue(messages -> { + // Filter out the command message + then.retrieveOriginal().queue(original -> { + if (original == null) return; + List toRemove = messages.stream().filter(message -> !original.getId().equals(message.getId())).toList(); + textChannel.deleteMessages(toRemove).queue(done -> then.editOriginalEmbeds(EmbedUtils.successEmbed() + .setDescription("Successfully purged `%s` messages\n\n*This message will be removed *".formatted( + amount, + (System.currentTimeMillis() + MESSAGE_DELETE_DELAY) / 1000 + )) + .build()).queue(message -> message.delete().queueAfter(MESSAGE_DELETE_DELAY, TimeUnit.MILLISECONDS))); + }); + }); + }); + } +} From 271a1cf88da980774e863ec40d232723a4cc5281 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 22:04:40 +0100 Subject: [PATCH 22/33] fix npe --- .../bat/features/logging/listeners/MemberListener.java | 2 +- src/main/java/cc/fascinated/bat/service/MongoService.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java index fbfd20b..0708a87 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/MemberListener.java @@ -64,7 +64,7 @@ public class MemberListener implements EventListener { @Override public void onGuildMemberLeave(@NonNull BatGuild guild, BatUser user, @NonNull GuildMemberRemoveEvent event) { - if (user.getDiscordUser().isBot()) return; + if (user == null || user.getDiscordUser().isBot()) return; log.info("User \"{}\" left the guild \"{}\"", user.getName(), guild.getDiscordGuild().getName()); logFeature.sendLog(guild, LogType.MEMBER_LEAVE, EmbedUtils.errorEmbed() diff --git a/src/main/java/cc/fascinated/bat/service/MongoService.java b/src/main/java/cc/fascinated/bat/service/MongoService.java index 93260bb..d1a8736 100644 --- a/src/main/java/cc/fascinated/bat/service/MongoService.java +++ b/src/main/java/cc/fascinated/bat/service/MongoService.java @@ -12,12 +12,12 @@ import org.springframework.stereotype.Service; @Service public class MongoService { public static MongoService INSTANCE; - private final MongoTemplate mongo; + private final MongoTemplate mongoTemplate; @Autowired public MongoService(MongoTemplate mongo) { INSTANCE = this; - this.mongo = mongo; + this.mongoTemplate = mongo; } /** @@ -26,7 +26,7 @@ public class MongoService { * @return The guilds collection */ public MongoCollection getGuildsCollection() { - return mongo.getCollection("guilds"); + return mongoTemplate.getCollection("guilds"); } /** @@ -35,6 +35,6 @@ public class MongoService { * @return The users collection */ public MongoCollection getUsersCollection() { - return mongo.getCollection("users"); + return mongoTemplate.getCollection("users"); } } From c2e447f4164d37698a47b43e5fb92277d038a275 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 22:10:35 +0100 Subject: [PATCH 23/33] fix welcomer placeholders and fix channel command --- .../bat/features/welcomer/WelcomerListener.java | 2 +- .../bat/features/welcomer/WelcomerProfile.java | 8 +++++--- .../welcomer/command/ChannelSubCommand.java | 17 ++++++++++++++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerListener.java b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerListener.java index b479891..e270847 100644 --- a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerListener.java +++ b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerListener.java @@ -27,6 +27,6 @@ public class WelcomerListener implements EventListener { } WelcomerProfile profile = guild.getWelcomerProfile(); - profile.sendWelcomeMessage(user); + profile.sendWelcomeMessage(guild, user); } } diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java index bccc48b..cf08dfb 100644 --- a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java +++ b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java @@ -1,6 +1,7 @@ package cc.fascinated.bat.features.welcomer; import cc.fascinated.bat.common.Serializable; +import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.DiscordService; import com.google.gson.Gson; @@ -72,9 +73,10 @@ public class WelcomerProfile extends Serializable { /** * Sends the welcome message to the user * + * @param guild The guild to send the message in * @param user The user to send the message to */ - public void sendWelcomeMessage(BatUser user) { + public void sendWelcomeMessage(BatGuild guild, BatUser user) { if (this.channel == null || (!this.isMessage() && !this.isEmbed())) { return; } @@ -82,11 +84,11 @@ public class WelcomerProfile extends Serializable { if (welcomerEmbed.isPingBeforeSend()) { // Ping the user before sending the message this.channel.sendMessage(user.getDiscordUser().getAsMention()).queue(); } - this.channel.sendMessageEmbeds(welcomerEmbed.buildEmbed(user).build()).queue(); + this.channel.sendMessageEmbeds(welcomerEmbed.buildEmbed(guild, user).build()).queue(); return; } if (welcomerMessage != null) { - this.channel.sendMessage(welcomerMessage.buildMessage(user)).queue(); + this.channel.sendMessage(welcomerMessage.buildMessage(guild, user)).queue(); } } diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/ChannelSubCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/ChannelSubCommand.java index d065a34..b91140e 100644 --- a/src/main/java/cc/fascinated/bat/features/welcomer/command/ChannelSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/ChannelSubCommand.java @@ -8,7 +8,10 @@ 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.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; import org.springframework.stereotype.Component; @@ -18,13 +21,21 @@ import org.springframework.stereotype.Component; @Component("welcomer:channel.sub") @CommandInfo(name = "channel", description = "Set the welcomer channel") public class ChannelSubCommand extends BatSubCommand { + public ChannelSubCommand() { + super.addOption(OptionType.CHANNEL, "channel", "The channel to send the welcomer messages to", true); + } + @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction event) { WelcomerProfile profile = guild.getWelcomerProfile(); - profile.setChannel(guild.getDiscordGuild().getTextChannelById(channel.getId())); - + OptionMapping channelOption = event.getOption("channel"); + if (channelOption == null) { + return; + } + TextChannel textChannel = channelOption.getAsChannel().asTextChannel(); + profile.setChannel(textChannel); event.replyEmbeds(EmbedUtils.successEmbed() - .setDescription("The welcomer channel has been set to %s".formatted(channel.getAsMention())) + .setDescription("The welcomer channel has been set to %s".formatted(textChannel.getAsMention())) .build()).queue(); } } From 642185f8c5db94d4a315c0dcd1d62da5f71975a7 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 22:12:56 +0100 Subject: [PATCH 24/33] fix welcomer serialization --- .../cc/fascinated/bat/features/welcomer/WelcomerProfile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java index cf08dfb..b3555f7 100644 --- a/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java +++ b/src/main/java/cc/fascinated/bat/features/welcomer/WelcomerProfile.java @@ -133,7 +133,7 @@ public class WelcomerProfile extends Serializable { ); } if (channel != null) { - document.put("channelId", channel.getIdLong()); + document.put("channelId", channel.getId()); } return document; } From 655662c6f8846141406293f0c18fb4b3c34a28dd Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 22:18:35 +0100 Subject: [PATCH 25/33] fix embed color --- .../bat/features/welcomer/command/EmbedSubCommand.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java b/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java index 3395cc8..4c6c283 100644 --- a/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/welcomer/command/EmbedSubCommand.java @@ -46,6 +46,9 @@ public class EmbedSubCommand extends BatSubCommand { String color = colorOption.getAsString(); boolean pingBeforeSend = pingBeforeSendOption.getAsBoolean(); + // Remove # if the user added it + color = color.replace("#", ""); + // Validate the input if (color.length() != 6 || Color.decode("#" + color).getRGB() == -1){ event.replyEmbeds(EmbedUtils.errorEmbed() @@ -67,7 +70,6 @@ public class EmbedSubCommand extends BatSubCommand { return; } - color = color.replace("#", ""); // Remove # if the user added it boolean isMessageEnabled = profile.isMessage(); profile.setEmbed(title, description, color, pingBeforeSend); EmbedDescriptionBuilder successDescription = new EmbedDescriptionBuilder("Welcomer Embed") From 2b4980fb10f35c0bbe13cebd3fe0a92350ec8a6b Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 22:18:51 +0100 Subject: [PATCH 26/33] change auto role log to include the guild --- .../bat/features/autorole/AutoRoleListener.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/features/autorole/AutoRoleListener.java b/src/main/java/cc/fascinated/bat/features/autorole/AutoRoleListener.java index ee501c1..eaa7dd3 100644 --- a/src/main/java/cc/fascinated/bat/features/autorole/AutoRoleListener.java +++ b/src/main/java/cc/fascinated/bat/features/autorole/AutoRoleListener.java @@ -49,7 +49,11 @@ public class AutoRoleListener implements EventListener { event.getGuild().addRoleToMember(event.getMember(), role).queue(); } toRemove.forEach(profile::removeRole); - log.info("Gave user \"{}\" {} auto roles{}", user.getId(), profile.getRoles().size(), toRemove.isEmpty() ? "" - : " and removed %s invalid roles".formatted(toRemove.size())); + log.info("Gave user \"{}\" {} auto roles in guild \"{}\"{}", + user.getId(), + profile.getRoles().size(), + guild.getName(), + toRemove.isEmpty() ? "" : " and removed %s invalid roles from the profile".formatted(toRemove.size()) + ); } } From a7a7bc784bf1308332817f9f5128b3b150279c6b Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 22:57:51 +0100 Subject: [PATCH 27/33] impl voice join and leave logging --- .../fascinated/bat/event/EventListener.java | 10 ++++++ .../bat/features/logging/LogType.java | 4 ++- .../logging/listeners/ChannelListener.java | 32 +++++++++++++++++++ .../fascinated/bat/service/EventService.java | 14 ++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/event/EventListener.java b/src/main/java/cc/fascinated/bat/event/EventListener.java index 80f8951..8ab8d5b 100644 --- a/src/main/java/cc/fascinated/bat/event/EventListener.java +++ b/src/main/java/cc/fascinated/bat/event/EventListener.java @@ -19,6 +19,7 @@ import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleAddEvent; import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent; import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent; import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateTimeOutEvent; +import net.dv8tion.jda.api.events.guild.voice.GenericGuildVoiceEvent; 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; @@ -232,6 +233,15 @@ public interface EventListener { default void onUserUpdateAvatar(@NonNull BatUser user, String oldAvatarUrl, String newAvatarUrl, @NonNull UserUpdateAvatarEvent event) { } + /** + * Called when a user joins or leaves a voice channel + * + * @param guild the guild that the user joined or left the voice channel in + * @param user the user that joined or left the voice channel + */ + default void onGuildVoiceUpdate(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GenericGuildVoiceEvent event) { + } + /** * Called when Spring is shutting down */ diff --git a/src/main/java/cc/fascinated/bat/features/logging/LogType.java b/src/main/java/cc/fascinated/bat/features/logging/LogType.java index d780b58..49e996e 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/LogType.java +++ b/src/main/java/cc/fascinated/bat/features/logging/LogType.java @@ -35,7 +35,9 @@ public enum LogType { * Channel Events */ CHANNEL_CREATE(LogCategory.CHANNEL, "Channel Create"), - CHANNEL_DELETE(LogCategory.CHANNEL, "Channel Delete"); + CHANNEL_DELETE(LogCategory.CHANNEL, "Channel Delete"), + VOICE_CHANNEL_JOIN(LogCategory.CHANNEL, "Voice Channel Join"), + VOICE_CHANNEL_LEAVE(LogCategory.CHANNEL, "Voice Channel Leave"); /** * The category of the log type diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java index 0e014f5..077626d 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java @@ -7,22 +7,33 @@ import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.logging.LogFeature; import cc.fascinated.bat.features.logging.LogType; import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; import lombok.NonNull; import lombok.extern.log4j.Log4j2; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel; +import net.dv8tion.jda.api.entities.channel.unions.AudioChannelUnion; import net.dv8tion.jda.api.entities.channel.unions.ChannelUnion; import net.dv8tion.jda.api.events.channel.ChannelCreateEvent; import net.dv8tion.jda.api.events.channel.ChannelDeleteEvent; +import net.dv8tion.jda.api.events.guild.voice.GenericGuildVoiceEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; +import java.util.HashMap; +import java.util.Map; + /** * @author Fascinated (fascinated7) */ @Component @Log4j2 public class ChannelListener implements EventListener { + /** + * A map of users and the last voice channel they were in + */ + private final Map lastVoiceChannel = new HashMap<>(); private final LogFeature logFeature; @Autowired @@ -53,4 +64,25 @@ public class ChannelListener implements EventListener { } logFeature.sendLog(guild, LogType.CHANNEL_DELETE, EmbedUtils.errorEmbed().setDescription(description.build()).build()); } + + @Override + public void onGuildVoiceUpdate(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GenericGuildVoiceEvent event) { + AudioChannelUnion channel = event.getVoiceState().getChannel(); + if (channel != null) { + VoiceChannel voiceChannel = channel.asVoiceChannel(); + lastVoiceChannel.put(user, voiceChannel); + } + VoiceChannel voiceChannel = lastVoiceChannel.get(user); + boolean joined = voiceChannel.getMembers().contains(event.getMember()); + if (!joined) { + lastVoiceChannel.remove(user); + } + log.info("User \"{}\" {} voice channel \"{}\" in guild \"{}\"", user.getId(), joined ? "joined" : "left", voiceChannel.getName(), guild.getName()); + logFeature.sendLog(guild, joined ? LogType.VOICE_CHANNEL_JOIN : LogType.VOICE_CHANNEL_LEAVE, EmbedUtils.successEmbed() + .setDescription(new EmbedDescriptionBuilder("User %s Voice Channel".formatted(joined ? "Joined" : "Left")) + .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) + .appendLine("Channel: %s".formatted(voiceChannel.getAsMention()), true) + .build()) + .build()); + } } diff --git a/src/main/java/cc/fascinated/bat/service/EventService.java b/src/main/java/cc/fascinated/bat/service/EventService.java index 7a672e9..4fd2fcc 100644 --- a/src/main/java/cc/fascinated/bat/service/EventService.java +++ b/src/main/java/cc/fascinated/bat/service/EventService.java @@ -16,6 +16,7 @@ import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleAddEvent; import net.dv8tion.jda.api.events.guild.member.GuildMemberRoleRemoveEvent; import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent; import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateTimeOutEvent; +import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent; 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; @@ -290,4 +291,17 @@ public class EventService extends ListenerAdapter { listener.onUserUpdateAvatar(user, event.getOldAvatarUrl(), event.getNewAvatarUrl(), event); } } + + @Override + public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) { + if (event.getEntity().getUser().isBot()) { + return; + } + BatGuild guild = guildService.getGuild(event.getEntity().getGuild().getId()); + BatUser user = userService.getUser(event.getEntity().getUser().getId()); + + for (EventListener listener : LISTENERS) { + listener.onGuildVoiceUpdate(guild, user, event); + } + } } From 5f75302f3afadb81b6a973eedb752268b54f05c7 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 22:59:05 +0100 Subject: [PATCH 28/33] don't make accounts for bots --- .../fascinated/bat/service/UserService.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/service/UserService.java b/src/main/java/cc/fascinated/bat/service/UserService.java index 69331c6..9f21057 100644 --- a/src/main/java/cc/fascinated/bat/service/UserService.java +++ b/src/main/java/cc/fascinated/bat/service/UserService.java @@ -8,6 +8,7 @@ import com.mongodb.client.model.Filters; import lombok.Getter; import lombok.NonNull; import lombok.extern.log4j.Log4j2; +import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent; import net.dv8tion.jda.api.events.user.update.UserUpdateGlobalNameEvent; import org.bson.Document; @@ -57,23 +58,28 @@ public class UserService implements EventListener { if (users.containsKey(id)) { return users.get(id); } - if (DiscordService.JDA.getUserById(id) == null) { - log.warn("Attempted to get user with ID \"{}\" but it does not exist", id); + User user = DiscordService.JDA.getUserById(id); + if (user == null) { + log.warn("Attempted to get user with ID \"{}\" but they do not exist", id); + return null; + } + if (user.isBot()) { + log.warn("Attempted to get user with ID \"{}\" but they are a bot", id); return null; } // User is not cached Document document = MongoService.INSTANCE.getUsersCollection().find(Filters.eq("_id", id)).first(); if (document != null) { - BatUser user = new BatUser(id, document); - users.put(id, user); - log.info("Loaded user \"{}\" in {}ms", user.getName(),System.currentTimeMillis() - before); - return user; + BatUser batUser = new BatUser(id, document); + users.put(id, batUser); + log.info("Loaded user \"{}\" in {}ms", batUser.getName(),System.currentTimeMillis() - before); + return batUser; } // New user - BatUser user = new BatUser(id, new Document()); - users.put(id, user); + BatUser batUser = new BatUser(id, new Document()); + users.put(id, batUser); log.info("Created user \"{}\" - \"{}\"", user.getName(), user.getId()); - return user; + return batUser; } @Override From 5959b814a77cd419a0b818f9bd9126293249dd34 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 23:01:56 +0100 Subject: [PATCH 29/33] use proper embed color for voice channel logs --- .../logging/listeners/ChannelListener.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java index 077626d..768dfaf 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java @@ -78,10 +78,19 @@ public class ChannelListener implements EventListener { lastVoiceChannel.remove(user); } log.info("User \"{}\" {} voice channel \"{}\" in guild \"{}\"", user.getId(), joined ? "joined" : "left", voiceChannel.getName(), guild.getName()); - logFeature.sendLog(guild, joined ? LogType.VOICE_CHANNEL_JOIN : LogType.VOICE_CHANNEL_LEAVE, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("User %s Voice Channel".formatted(joined ? "Joined" : "Left")) + if (joined) { + logFeature.sendLog(guild, LogType.VOICE_CHANNEL_JOIN, EmbedUtils.successEmbed() + .setDescription(new EmbedDescriptionBuilder("User Joined Voice Channel") + .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) + .appendLine("Channel: %s".formatted(voiceChannel.getName()), true) + .build()) + .build()); + return; + } + logFeature.sendLog(guild, LogType.VOICE_CHANNEL_LEAVE, EmbedUtils.errorEmbed() + .setDescription(new EmbedDescriptionBuilder("User Left Voice Channel") .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) - .appendLine("Channel: %s".formatted(voiceChannel.getAsMention()), true) + .appendLine("Channel: %s".formatted(voiceChannel.getName()), true) .build()) .build()); } From 938005f6d9a972d5dc51aed3ed80f2731a582e19 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 23:02:42 +0100 Subject: [PATCH 30/33] add null check --- .../bat/features/logging/listeners/ChannelListener.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java index 768dfaf..4416f14 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java @@ -73,6 +73,9 @@ public class ChannelListener implements EventListener { lastVoiceChannel.put(user, voiceChannel); } VoiceChannel voiceChannel = lastVoiceChannel.get(user); + if (voiceChannel == null) { + return; + } boolean joined = voiceChannel.getMembers().contains(event.getMember()); if (!joined) { lastVoiceChannel.remove(user); From 831bc934b4cc741ea862bac6fb44e8192506c537 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 23:07:50 +0100 Subject: [PATCH 31/33] cleanup voice logs --- .../logging/listeners/ChannelListener.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java index 4416f14..1dbf1ec 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java @@ -81,20 +81,14 @@ public class ChannelListener implements EventListener { lastVoiceChannel.remove(user); } log.info("User \"{}\" {} voice channel \"{}\" in guild \"{}\"", user.getId(), joined ? "joined" : "left", voiceChannel.getName(), guild.getName()); + String description = new EmbedDescriptionBuilder("User %s Voice Channel".formatted(joined ? "Joined" : "Left")) + .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) + .appendLine("Channel: %s".formatted(voiceChannel.getName()), true) + .build(); if (joined) { - logFeature.sendLog(guild, LogType.VOICE_CHANNEL_JOIN, EmbedUtils.successEmbed() - .setDescription(new EmbedDescriptionBuilder("User Joined Voice Channel") - .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) - .appendLine("Channel: %s".formatted(voiceChannel.getName()), true) - .build()) - .build()); + logFeature.sendLog(guild, LogType.VOICE_CHANNEL_JOIN, EmbedUtils.successEmbed().setDescription(description).build()); return; } - logFeature.sendLog(guild, LogType.VOICE_CHANNEL_LEAVE, EmbedUtils.errorEmbed() - .setDescription(new EmbedDescriptionBuilder("User Left Voice Channel") - .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) - .appendLine("Channel: %s".formatted(voiceChannel.getName()), true) - .build()) - .build()); + logFeature.sendLog(guild, LogType.VOICE_CHANNEL_LEAVE, EmbedUtils.errorEmbed().setDescription(description).build()); } } From 3878d3029bf547c5925812b9e91fcae04864163c Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 23:09:28 +0100 Subject: [PATCH 32/33] mention voice channel in the embed --- .../bat/features/logging/listeners/ChannelListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java index 1dbf1ec..ddfc40b 100644 --- a/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java +++ b/src/main/java/cc/fascinated/bat/features/logging/listeners/ChannelListener.java @@ -83,7 +83,7 @@ public class ChannelListener implements EventListener { log.info("User \"{}\" {} voice channel \"{}\" in guild \"{}\"", user.getId(), joined ? "joined" : "left", voiceChannel.getName(), guild.getName()); String description = new EmbedDescriptionBuilder("User %s Voice Channel".formatted(joined ? "Joined" : "Left")) .appendLine("User: %s".formatted(user.getDiscordUser().getAsMention()), true) - .appendLine("Channel: %s".formatted(voiceChannel.getName()), true) + .appendLine("Channel: %s".formatted(voiceChannel.getAsMention()), true) .build(); if (joined) { logFeature.sendLog(guild, LogType.VOICE_CHANNEL_JOIN, EmbedUtils.successEmbed().setDescription(description).build()); From bd9ac1e138b997f21813a59e10eae6e75e45dac4 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 3 Jul 2024 23:23:23 +0100 Subject: [PATCH 33/33] maybe fix npe?? --- .../java/cc/fascinated/bat/model/BatGuild.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/cc/fascinated/bat/model/BatGuild.java b/src/main/java/cc/fascinated/bat/model/BatGuild.java index fb40213..8b886a5 100644 --- a/src/main/java/cc/fascinated/bat/model/BatGuild.java +++ b/src/main/java/cc/fascinated/bat/model/BatGuild.java @@ -49,11 +49,21 @@ public class BatGuild extends ProfileHolder { */ private Date createdAt; + /** + * The guild as the JDA Guild + */ + private Guild guild; + public BatGuild(@NonNull String id, @NonNull org.bson.Document document) { this.id = id; this.document = document; boolean newAccount = this.document.isEmpty(); this.createdAt = newAccount ? new Date() : document.getDate("createdAt"); + + Guild guild = DiscordService.JDA.getGuildById(id); + if (guild != null) { + this.guild = guild; + } } /** @@ -71,7 +81,10 @@ public class BatGuild extends ProfileHolder { * @return the guild */ public Guild getDiscordGuild() { - return DiscordService.JDA.getGuildById(id); + if (guild == null) { + guild = DiscordService.JDA.getGuildById(id); + } + return guild; } /**