diff --git a/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java b/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java index 3146132..afab2aa 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java @@ -1,13 +1,16 @@ package cc.fascinated.bat.features.birthday; import cc.fascinated.bat.command.Category; +import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.Feature; import cc.fascinated.bat.features.birthday.command.BirthdayCommand; import cc.fascinated.bat.features.birthday.profile.BirthdayProfile; import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.CommandService; import cc.fascinated.bat.service.GuildService; import lombok.NonNull; +import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent; import org.springframework.context.ApplicationContext; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -16,7 +19,7 @@ import org.springframework.stereotype.Component; * @author Fascinated (fascinated7) */ @Component -public class BirthdayFeature extends Feature { +public class BirthdayFeature extends Feature implements EventListener { private final GuildService guildService; public BirthdayFeature(@NonNull ApplicationContext context, @NonNull CommandService commandService, @NonNull GuildService guildService) { @@ -26,6 +29,13 @@ public class BirthdayFeature extends Feature { registerCommand(commandService, context.getBean(BirthdayCommand.class)); } + @Override + public void onGuildMemberLeave(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberRemoveEvent event) { + BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); + profile.removeBirthday(user.getId()); + guildService.saveGuild(guild); + } + /** * Check birthdays every day at midnight */ diff --git a/src/main/java/cc/fascinated/bat/features/birthday/UserBirthday.java b/src/main/java/cc/fascinated/bat/features/birthday/UserBirthday.java index 70471e7..63ca047 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/UserBirthday.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/UserBirthday.java @@ -5,6 +5,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import java.util.Calendar; import java.util.Date; /** @@ -24,4 +25,25 @@ public class UserBirthday { * If the birthday should be hidden */ private boolean hidden; + + /** + * Calculates the age of the user + * + * @return the age of the user + */ + public int calculateAge() { + Calendar birthdayCalendar = Calendar.getInstance(); + birthdayCalendar.setTime(this.getBirthday()); + + Calendar today = Calendar.getInstance(); + + int age = today.get(Calendar.YEAR) - birthdayCalendar.get(Calendar.YEAR); + + // Check if the birthday hasn't occurred yet this year + if (today.get(Calendar.DAY_OF_YEAR) < birthdayCalendar.get(Calendar.DAY_OF_YEAR)) { + age--; + } + + return age; + } } diff --git a/src/main/java/cc/fascinated/bat/features/birthday/command/MessageSubCommand.java b/src/main/java/cc/fascinated/bat/features/birthday/command/MessageSubCommand.java index 216b0d3..2b9edde 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/command/MessageSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/command/MessageSubCommand.java @@ -28,7 +28,6 @@ import java.util.Date; @Component("birthday:message.sub") @CommandInfo(name = "message", description = "Changes the message that is sent when it is a user's birthday", requiredPermissions = Permission.MANAGE_SERVER) public class MessageSubCommand extends BatSubCommand { - private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("dd/MM/yyyy"); private final GuildService guildService; @Autowired @@ -40,7 +39,6 @@ public class MessageSubCommand extends BatSubCommand { @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); - OptionMapping messageOption = interaction.getOption("message"); if (messageOption == null) { interaction.replyEmbeds(EmbedUtils.errorEmbed() @@ -65,23 +63,8 @@ public class MessageSubCommand extends BatSubCommand { profile.setMessage(message); guildService.saveGuild(guild); - interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("You have updated the birthday message!\n\n**Message:** %s".formatted(profile.getBirthdayMessage(user.getDiscordUser()))) .build()).queue(); } - - /** - * Parses a birthday from the string - * - * @param birthday the date to parse - * @return the birthday - */ - private Date parseBirthday(String birthday) { - try { - return FORMATTER.parse(birthday); - } catch (ParseException ignored) { - } - return null; - } } diff --git a/src/main/java/cc/fascinated/bat/features/birthday/command/SetSubCommand.java b/src/main/java/cc/fascinated/bat/features/birthday/command/SetSubCommand.java index 245850f..5eb9598 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/command/SetSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/command/SetSubCommand.java @@ -40,7 +40,6 @@ public class SetSubCommand extends BatSubCommand { @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); - if (!profile.hasChannelSetup()) { interaction.replyEmbeds(EmbedUtils.errorEmbed() .setDescription("Birthdays have not been enabled in this guild. Please ask an administrator to enable them.") diff --git a/src/main/java/cc/fascinated/bat/features/birthday/command/ViewSubCommand.java b/src/main/java/cc/fascinated/bat/features/birthday/command/ViewSubCommand.java index 56cf3af..0f55487 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/command/ViewSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/command/ViewSubCommand.java @@ -8,6 +8,7 @@ import cc.fascinated.bat.features.birthday.profile.BirthdayProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.GuildService; +import cc.fascinated.bat.service.UserService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; @@ -24,15 +25,17 @@ import org.springframework.stereotype.Component; @Component("birthday:view.sub") @CommandInfo(name = "view", description = "Add your birthday to this guild") public class ViewSubCommand extends BatSubCommand { + private final UserService userService; + @Autowired - public ViewSubCommand(GuildService guildService) { + public ViewSubCommand(@NonNull UserService userService) { + this.userService = userService; super.addOption(OptionType.USER, "user", "The user to view the birthday of", false); } @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); - if (!profile.hasChannelSetup()) { interaction.replyEmbeds(EmbedUtils.errorEmbed() .setDescription("Birthdays have not been enabled in this guild. Please ask an administrator to enable them.") @@ -41,36 +44,32 @@ public class ViewSubCommand extends BatSubCommand { } OptionMapping birthdayOption = interaction.getOption("user"); - if (birthdayOption == null) { - interaction.replyEmbeds(EmbedUtils.errorEmbed() - .setDescription("You must provide a birthday") - .build()).queue(); - return; - } - - Member targetMember = birthdayOption.getAsMember(); - if (targetMember == null) { + BatUser target = birthdayOption == null ? user : userService.getUser(birthdayOption.getAsUser().getId()); + if (target == null) { interaction.replyEmbeds(EmbedUtils.errorEmbed() .setDescription("You must provide a valid user") .build()).queue(); return; } - UserBirthday birthday = profile.getBirthday(targetMember.getId()); + UserBirthday birthday = profile.getBirthday(target.getId()); if (birthday == null) { interaction.replyEmbeds(EmbedUtils.errorEmbed() - .setDescription("This user does not have a birthday set") + .setDescription("%s does not have a birthday set".formatted(target.getDiscordUser().getAsMention())) .build()).queue(); return; } - if (birthday.isHidden() && !user.getId().equals(targetMember.getId())) { + if (birthday.isHidden() && !user.getId().equals(target.getId())) { interaction.replyEmbeds(EmbedUtils.errorEmbed() - .setDescription("%s has their birthday set to private".formatted(targetMember.getAsMention())) + .setDescription("%s has their birthday set to private".formatted(target.getDiscordUser().getAsMention())) .build()).queue(); return; } interaction.replyEmbeds(EmbedUtils.successEmbed() - .setDescription("%s's birthday is ".formatted(member.getAsMention(), birthday.getBirthday().toInstant().toEpochMilli()/1000)) + .setDescription("%s was born on they are `%s` years old!".formatted( + target.getDiscordUser().getAsMention(), birthday.getBirthday().toInstant().toEpochMilli()/1000, + birthday.calculateAge() + )) .build()).queue(); } } diff --git a/src/main/java/cc/fascinated/bat/features/birthday/profile/BirthdayProfile.java b/src/main/java/cc/fascinated/bat/features/birthday/profile/BirthdayProfile.java index e264396..5f72745 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/profile/BirthdayProfile.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/profile/BirthdayProfile.java @@ -86,33 +86,6 @@ public class BirthdayProfile extends Profile { return channelId != null; } - /** - * Calculates the age of a user - * - * @param userId the id of the user - * @return the age of the user - */ - public int calculateAge(String userId) { - UserBirthday birthday = getBirthday(userId); - if (birthday == null) { - return 0; // or throw an exception - } - - Calendar birthdayCalendar = Calendar.getInstance(); - birthdayCalendar.setTime(birthday.getBirthday()); - - Calendar today = Calendar.getInstance(); - - int age = today.get(Calendar.YEAR) - birthdayCalendar.get(Calendar.YEAR); - - // Check if the birthday hasn't occurred yet this year - if (today.get(Calendar.DAY_OF_YEAR) < birthdayCalendar.get(Calendar.DAY_OF_YEAR)) { - age--; - } - - return age; - } - /** * Validates the profiles configuration * @@ -221,7 +194,7 @@ public class BirthdayProfile extends Profile { public String getBirthdayMessage(User user) { return message .replace("{user}", user.getAsMention()) - .replace("{age}", String.valueOf(calculateAge(user.getId()))); + .replace("{age}", String.valueOf(birthdays.get(user.getId()).calculateAge())); } @Override diff --git a/src/main/java/cc/fascinated/bat/changelog/BirthdayProfileChangelog.java b/src/main/java/cc/fascinated/bat/migrations/BirthdayProfileChangelog.java similarity index 91% rename from src/main/java/cc/fascinated/bat/changelog/BirthdayProfileChangelog.java rename to src/main/java/cc/fascinated/bat/migrations/BirthdayProfileChangelog.java index 0882fa2..2413a8a 100644 --- a/src/main/java/cc/fascinated/bat/changelog/BirthdayProfileChangelog.java +++ b/src/main/java/cc/fascinated/bat/migrations/BirthdayProfileChangelog.java @@ -1,4 +1,4 @@ -package cc.fascinated.bat.changelog; +package cc.fascinated.bat.migrations; import com.mongodb.client.FindIterable; import io.mongock.api.annotations.ChangeUnit; @@ -7,8 +7,6 @@ import io.mongock.api.annotations.RollbackExecution; import org.bson.Document; import org.springframework.data.mongodb.core.MongoTemplate; -import javax.print.Doc; - /** * @author Fascinated (fascinated7) */ @@ -29,6 +27,9 @@ public class BirthdayProfileChangelog { return; } Document birthdayProfile = profiles.get("birthday", Document.class); + if (birthdayProfile == null) { + return; + } birthdayProfile.remove("birthdays"); profiles.put("birthday", birthdayProfile); guild.put("profiles", profiles); diff --git a/src/main/java/cc/fascinated/bat/changelog/MongockSuccessEventListener.java b/src/main/java/cc/fascinated/bat/migrations/MongockSuccessEventListener.java similarity index 93% rename from src/main/java/cc/fascinated/bat/changelog/MongockSuccessEventListener.java rename to src/main/java/cc/fascinated/bat/migrations/MongockSuccessEventListener.java index 3270352..6fd1dae 100644 --- a/src/main/java/cc/fascinated/bat/changelog/MongockSuccessEventListener.java +++ b/src/main/java/cc/fascinated/bat/migrations/MongockSuccessEventListener.java @@ -1,4 +1,4 @@ -package cc.fascinated.bat.changelog; +package cc.fascinated.bat.migrations; import io.mongock.runner.spring.base.events.SpringMigrationSuccessEvent; import lombok.extern.log4j.Log4j2; diff --git a/src/main/java/cc/fascinated/bat/service/CommandService.java b/src/main/java/cc/fascinated/bat/service/CommandService.java index f1e6c2e..1a4c030 100644 --- a/src/main/java/cc/fascinated/bat/service/CommandService.java +++ b/src/main/java/cc/fascinated/bat/service/CommandService.java @@ -213,6 +213,7 @@ public class CommandService extends ListenerAdapter { executor.execute(guild, user, ranInsideGuild ? event.getChannel().asTextChannel() : event.getChannel().asPrivateChannel(), event.getMember(), event.getInteraction()); } catch (Exception ex) { + log.error("An error occurred while executing command \"{}\"", commandName, ex); event.replyEmbeds(EmbedUtils.errorEmbed() .setDescription(ex.getLocalizedMessage()) .build()) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0bc0ac0..b3779f0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -8,6 +8,10 @@ sentry: tracesSampleRate: 1.0 environment: "development" +# MongoDB Migration Configuration +mongock: + change-logs-scan-package: "cc.fascinated.bat.changelog" + # Spotify Configuration spotify: redirect-uri: "http://localhost:8080/spotify/callback"