From d372c41c98c4355438bc7d530393ec4fa6c59c21 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 1 Jul 2024 01:12:32 +0100 Subject: [PATCH] big ass refactor to handle loading guilds and users without spring to make it more futureproof --- .../cc/fascinated/bat/common/Profile.java | 25 --- .../fascinated/bat/common/ProfileHolder.java | 35 ++-- .../fascinated/bat/common/Serializable.java | 36 ++++ .../bat/features/afk/AfkReturnListener.java | 10 -- .../bat/features/afk/command/AfkCommand.java | 9 +- .../bat/features/afk/profile/AfkProfile.java | 29 +++- .../autorole/command/AddSubCommand.java | 7 +- .../autorole/command/ClearSubCommand.java | 10 -- .../autorole/command/RemoveSubCommand.java | 7 +- .../autorole/profile/AutoRoleProfile.java | 26 ++- .../botadmin/premium/RemoveSubCommand.java | 4 +- .../botadmin/premium/SetSubCommand.java | 6 +- .../base/commands/server/PremiumCommand.java | 3 +- .../server/feature/DisableSubCommand.java | 11 +- .../server/feature/EnableSubCommand.java | 7 +- .../features/base/profile/FeatureProfile.java | 37 ++-- .../features/birthday/BirthdayFeature.java | 7 +- .../bat/features/birthday/UserBirthday.java | 28 ++- .../birthday/command/ChannelSubCommand.java | 10 +- .../birthday/command/MessageSubCommand.java | 9 +- .../birthday/command/PrivateSubCommand.java | 10 +- .../birthday/command/RemoveSubCommand.java | 13 +- .../birthday/command/SetSubCommand.java | 14 +- .../birthday/command/ViewSubCommand.java | 2 +- .../birthday/profile/BirthdayProfile.java | 35 +++- .../namehistory/NameHistoryListener.java | 7 +- .../bat/features/namehistory/TrackedName.java | 30 +++- .../profile/guild/NameHistoryProfile.java | 47 +++++- .../profile/user/NameHistoryProfile.java | 45 ++++- .../NumberOneScoreFeedListener.java | 1 - .../scoresaber/UserScoreFeedListener.java | 1 - .../command/numberone/ChannelSubCommand.java | 8 +- .../command/numberone/ResetSubCommand.java | 10 -- .../command/scoresaber/LinkSubCommand.java | 6 +- .../command/scoresaber/ResetSubCommand.java | 10 -- .../command/userfeed/ChannelSubCommand.java | 8 +- .../command/userfeed/ResetSubCommand.java | 11 -- .../command/userfeed/UserSubCommand.java | 1 - .../guild/NumberOneScoreFeedProfile.java | 24 ++- .../profile/guild/UserScoreFeedProfile.java | 26 ++- .../profile/user/ScoreSaberProfile.java | 24 ++- .../spotify/command/UnlinkSubCommand.java | 10 -- .../spotify/profile/SpotifyProfile.java | 26 ++- .../changelogs/BirthdayProfileChangelog.java | 44 ----- ...oresaberProfileRenamePackageChangelog.java | 86 ---------- .../cc/fascinated/bat/model/BatGuild.java | 159 +++++++----------- .../java/cc/fascinated/bat/model/BatUser.java | 48 +++++- .../bat/premium/PremiumProfile.java | 134 +++++++++++++++ .../bat/repository/GuildRepository.java | 10 -- .../bat/repository/UserRepository.java | 10 -- .../bat/service/CommandService.java | 2 +- .../bat/service/DiscordService.java | 4 + .../fascinated/bat/service/EventService.java | 2 +- .../bat/service/FeatureService.java | 2 +- .../fascinated/bat/service/GuildService.java | 102 ++++++----- .../fascinated/bat/service/MongoService.java | 40 +++++ .../bat/service/SpotifyService.java | 4 +- .../fascinated/bat/service/UserService.java | 61 ++++--- 58 files changed, 755 insertions(+), 638 deletions(-) delete mode 100644 src/main/java/cc/fascinated/bat/common/Profile.java create mode 100644 src/main/java/cc/fascinated/bat/common/Serializable.java delete mode 100644 src/main/java/cc/fascinated/bat/migrations/changelogs/BirthdayProfileChangelog.java delete mode 100644 src/main/java/cc/fascinated/bat/migrations/changelogs/ScoresaberProfileRenamePackageChangelog.java create mode 100644 src/main/java/cc/fascinated/bat/premium/PremiumProfile.java delete mode 100644 src/main/java/cc/fascinated/bat/repository/GuildRepository.java delete mode 100644 src/main/java/cc/fascinated/bat/repository/UserRepository.java create mode 100644 src/main/java/cc/fascinated/bat/service/MongoService.java diff --git a/src/main/java/cc/fascinated/bat/common/Profile.java b/src/main/java/cc/fascinated/bat/common/Profile.java deleted file mode 100644 index fb23c1d..0000000 --- a/src/main/java/cc/fascinated/bat/common/Profile.java +++ /dev/null @@ -1,25 +0,0 @@ -package cc.fascinated.bat.common; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -/** - * @author Fascinated (fascinated7) - */ -@AllArgsConstructor -@NoArgsConstructor -@Getter -@Setter -public abstract class Profile { - /** - * The key of the profile. - */ - private String profileKey; - - /** - * Resets the profile - */ - public abstract void reset(); -} diff --git a/src/main/java/cc/fascinated/bat/common/ProfileHolder.java b/src/main/java/cc/fascinated/bat/common/ProfileHolder.java index 42a9435..8def165 100644 --- a/src/main/java/cc/fascinated/bat/common/ProfileHolder.java +++ b/src/main/java/cc/fascinated/bat/common/ProfileHolder.java @@ -1,6 +1,9 @@ package cc.fascinated.bat.common; +import cc.fascinated.bat.BatApplication; import lombok.Getter; +import lombok.SneakyThrows; +import org.bson.Document; import java.util.HashMap; import java.util.Map; @@ -9,11 +12,11 @@ import java.util.Map; * @author Fascinated (fascinated7) */ @Getter -public class ProfileHolder { +public abstract class ProfileHolder { /** * The profiles for the holder */ - private Map profiles; + private final Map profiles = new HashMap<>(); /** * Gets a profile for the holder @@ -22,19 +25,25 @@ public class ProfileHolder { * @param The type of the profile * @return The profile */ - public T getProfile(Class clazz) { - if (profiles == null) { - profiles = new HashMap<>(); - } + public abstract T getProfile(Class clazz); - Profile profile = profiles.values().stream().filter(clazz::isInstance).findFirst().orElse(null); + /** + * Gets the profiles for the holder + * using the provided document + * + * @return the profiles + */ + @SneakyThrows + protected T getProfileFromDocument(Class clazz, Document document) { + Serializable profile = getProfiles().get(clazz.getSimpleName()); if (profile == null) { - try { - profile = clazz.newInstance(); - profiles.put(profile.getProfileKey(), profile); - } catch (InstantiationException | IllegalAccessException e) { - e.printStackTrace(); - } + T newProfile = clazz.cast(clazz.getDeclaredConstructors()[0].newInstance()); + org.bson.Document profiles = document.get("profiles", new org.bson.Document()); + org.bson.Document profileDocument = (org.bson.Document) profiles.getOrDefault(clazz.getSimpleName(), new org.bson.Document()); + + newProfile.load(profileDocument, BatApplication.GSON); + getProfiles().put(clazz.getSimpleName(), newProfile); + return newProfile; } return clazz.cast(profile); } diff --git a/src/main/java/cc/fascinated/bat/common/Serializable.java b/src/main/java/cc/fascinated/bat/common/Serializable.java new file mode 100644 index 0000000..fe73ef2 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/common/Serializable.java @@ -0,0 +1,36 @@ +package cc.fascinated.bat.common; + +import com.google.gson.Gson; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.bson.Document; + +/** + * @author Fascinated (fascinated7) + */ +@Setter +@Getter +@NoArgsConstructor +public abstract class Serializable { + /** + * Load data from the provided document into this profile + * + * @param document the document to load data from + * @param gson the GSON instance to use + */ + public abstract void load(Document document, Gson gson); + + /** + * Serialize this profile into a Bson document + * + * @param gson the GSON instance to use + * @return the serialized document + */ + public abstract Document serialize(Gson gson); + + /** + * Resets the profile to its default state + */ + public abstract void reset(); +} diff --git a/src/main/java/cc/fascinated/bat/features/afk/AfkReturnListener.java b/src/main/java/cc/fascinated/bat/features/afk/AfkReturnListener.java index 62d8b05..c23a3c7 100644 --- a/src/main/java/cc/fascinated/bat/features/afk/AfkReturnListener.java +++ b/src/main/java/cc/fascinated/bat/features/afk/AfkReturnListener.java @@ -4,10 +4,8 @@ import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.features.afk.profile.AfkProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -15,13 +13,6 @@ import org.springframework.stereotype.Component; */ @Component public class AfkReturnListener implements EventListener { - private final GuildService guildService; - - @Autowired - public AfkReturnListener(@NonNull GuildService guildService) { - this.guildService = guildService; - } - @Override public void onGuildMessageReceive(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull MessageReceivedEvent event) { AfkProfile profile = guild.getProfile(AfkProfile.class); @@ -29,7 +20,6 @@ public class AfkReturnListener implements EventListener { return; } profile.removeAfkUser(guild, user.getId()); - guildService.saveGuild(guild); event.getMessage().reply("Welcome back, %s! You are no longer AFK.".formatted(user.getDiscordUser().getAsMention())).queue(); } } diff --git a/src/main/java/cc/fascinated/bat/features/afk/command/AfkCommand.java b/src/main/java/cc/fascinated/bat/features/afk/command/AfkCommand.java index e99c533..cd27a09 100644 --- a/src/main/java/cc/fascinated/bat/features/afk/command/AfkCommand.java +++ b/src/main/java/cc/fascinated/bat/features/afk/command/AfkCommand.java @@ -6,14 +6,12 @@ import cc.fascinated.bat.common.MemberUtils; import cc.fascinated.bat.features.afk.profile.AfkProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.GuildService; 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.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -22,11 +20,7 @@ import org.springframework.stereotype.Component; @Component @CommandInfo(name = "afk", description = "Sets your AFK status") public class AfkCommand extends BatCommand { - private final GuildService guildService; - - @Autowired - public AfkCommand(@NonNull GuildService guildService) { - this.guildService = guildService; + public AfkCommand() { super.addOption(OptionType.STRING, "reason", "The reason for being AFK", false); } @@ -40,7 +34,6 @@ public class AfkCommand extends BatCommand { } profile.addAfkUser(guild, member.getId(), reason); - guildService.saveGuild(guild); interaction.reply("You are now AFK: %s%s".formatted( profile.getAfkReason(member.getId()), MemberUtils.hasPermissionToEdit(guild, user) ? "" : diff --git a/src/main/java/cc/fascinated/bat/features/afk/profile/AfkProfile.java b/src/main/java/cc/fascinated/bat/features/afk/profile/AfkProfile.java index 06f60ba..d8fafdc 100644 --- a/src/main/java/cc/fascinated/bat/features/afk/profile/AfkProfile.java +++ b/src/main/java/cc/fascinated/bat/features/afk/profile/AfkProfile.java @@ -1,9 +1,12 @@ package cc.fascinated.bat.features.afk.profile; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.model.BatGuild; +import com.google.gson.Gson; +import lombok.NoArgsConstructor; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; +import org.bson.Document; import org.springframework.stereotype.Component; import java.util.HashMap; @@ -13,7 +16,8 @@ import java.util.Map; * @author Fascinated (fascinated7) */ @Component -public class AfkProfile extends Profile { +@NoArgsConstructor +public class AfkProfile extends Serializable { private static final String DEFAULT_REASON = "Away"; /** @@ -21,10 +25,6 @@ public class AfkProfile extends Profile { */ private Map afkUsers; - public AfkProfile() { - super("afk"); - } - /** * Adds a user to the AFK list * @@ -102,4 +102,21 @@ public class AfkProfile extends Profile { public void reset() { afkUsers = new HashMap<>(); } + + @Override + public void load(Document document, Gson gson) { + afkUsers = new HashMap<>(); + for (String key : document.keySet()) { + afkUsers.put(key, document.getString(key)); + } + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + for (String key : afkUsers.keySet()) { + document.put(key, afkUsers.get(key)); + } + return document; + } } diff --git a/src/main/java/cc/fascinated/bat/features/autorole/command/AddSubCommand.java b/src/main/java/cc/fascinated/bat/features/autorole/command/AddSubCommand.java index fd3586d..7338752 100644 --- a/src/main/java/cc/fascinated/bat/features/autorole/command/AddSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/autorole/command/AddSubCommand.java @@ -7,7 +7,6 @@ import cc.fascinated.bat.common.RoleUtils; import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; @@ -24,12 +23,9 @@ import org.springframework.stereotype.Component; @Component("autoroles:add.sub") @CommandInfo(name = "add", description = "Adds a role to the auto roles list") public class AddSubCommand extends BatSubCommand { - private final GuildService guildService; - @Autowired - public AddSubCommand(@NonNull GuildService guildService) { + public AddSubCommand() { super.addOption(OptionType.ROLE, "role", "The role to add", true); - this.guildService = guildService; } @Override @@ -80,7 +76,6 @@ public class AddSubCommand extends BatSubCommand { // Add the role to the auto roles list profile.addRole(role.getId()); - guildService.saveGuild(guild); interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("You have added %s to the auto roles list".formatted(role.getAsMention())) .build()).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/autorole/command/ClearSubCommand.java b/src/main/java/cc/fascinated/bat/features/autorole/command/ClearSubCommand.java index 0ea174b..1ed1526 100644 --- a/src/main/java/cc/fascinated/bat/features/autorole/command/ClearSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/autorole/command/ClearSubCommand.java @@ -6,12 +6,10 @@ import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.GuildService; 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.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -20,19 +18,11 @@ import org.springframework.stereotype.Component; @Component("autoroles:clear.sub") @CommandInfo(name = "clear", description = "Clears all auto roles") public class ClearSubCommand extends BatSubCommand { - private final GuildService guildService; - - @Autowired - public ClearSubCommand(GuildService guildService) { - this.guildService = guildService; - } - @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { AutoRoleProfile profile = guild.getProfile(AutoRoleProfile.class); profile.reset(); - guildService.saveGuild(guild); interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully cleared all auto roles") .build()).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/autorole/command/RemoveSubCommand.java b/src/main/java/cc/fascinated/bat/features/autorole/command/RemoveSubCommand.java index e75212b..98ed6fe 100644 --- a/src/main/java/cc/fascinated/bat/features/autorole/command/RemoveSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/autorole/command/RemoveSubCommand.java @@ -6,7 +6,6 @@ import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.autorole.profile.AutoRoleProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; @@ -23,12 +22,9 @@ import org.springframework.stereotype.Component; @Component("autoroles:remove.sub") @CommandInfo(name = "remove", description = "Removes a role from the auto roles list") public class RemoveSubCommand extends BatSubCommand { - private final GuildService guildService; - @Autowired - public RemoveSubCommand(GuildService guildService) { + public RemoveSubCommand() { super.addOption(OptionType.ROLE, "role", "The role to remove", true); - this.guildService = guildService; } @Override @@ -51,7 +47,6 @@ public class RemoveSubCommand extends BatSubCommand { } profile.removeRole(role.getId()); - guildService.saveGuild(guild); interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully removed the role %s from the auto roles list".formatted(role.getAsMention())) .build()).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/autorole/profile/AutoRoleProfile.java b/src/main/java/cc/fascinated/bat/features/autorole/profile/AutoRoleProfile.java index 80608dd..f93f6f4 100644 --- a/src/main/java/cc/fascinated/bat/features/autorole/profile/AutoRoleProfile.java +++ b/src/main/java/cc/fascinated/bat/features/autorole/profile/AutoRoleProfile.java @@ -1,11 +1,14 @@ package cc.fascinated.bat.features.autorole.profile; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.service.DiscordService; +import com.google.gson.Gson; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import net.dv8tion.jda.api.entities.Role; +import org.bson.Document; import java.util.ArrayList; import java.util.List; @@ -15,7 +18,8 @@ import java.util.List; */ @Setter @Getter -public class AutoRoleProfile extends Profile { +@NoArgsConstructor +public class AutoRoleProfile extends Serializable { private static final int DEFAULT_MAX_ROLES = 10; private static final int PREMIUM_MAX_ROLES = 25; @@ -24,10 +28,6 @@ public class AutoRoleProfile extends Profile { */ private List roleIds; - public AutoRoleProfile() { - super("auto-role"); - } - /** * Gets the maximum amount of roles that can be set in the guild * @@ -35,7 +35,7 @@ public class AutoRoleProfile extends Profile { * @return the amount of role slots */ public static int getMaxRoleSlots(BatGuild guild) { - if (guild.getPremium().hasPremium()) { + if (guild.getPremiumProfile().hasPremium()) { return PREMIUM_MAX_ROLES; } return DEFAULT_MAX_ROLES; @@ -110,4 +110,16 @@ public class AutoRoleProfile extends Profile { public void reset() { roleIds.clear(); } + + @Override + public void load(Document document, Gson gson) { + roleIds = document.getList("roleIds", String.class); + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + document.put("roleIds", roleIds); + return document; + } } diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/botadmin/premium/RemoveSubCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/botadmin/premium/RemoveSubCommand.java index a70a29f..b73ec94 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/botadmin/premium/RemoveSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/botadmin/premium/RemoveSubCommand.java @@ -4,6 +4,7 @@ import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.command.CommandInfo; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.premium.PremiumProfile; import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; @@ -41,14 +42,13 @@ public class RemoveSubCommand extends BatSubCommand { interaction.reply("The guild with the id %s does not exist".formatted(guildId)).queue(); return; } - BatGuild.Premium premium = batGuild.getPremium(); + PremiumProfile premium = batGuild.getPremiumProfile(); if (!premium.hasPremium()) { interaction.reply("The guild does not have premium").queue(); return; } premium.removePremium(); - guildService.saveGuild(batGuild); interaction.reply("The guild **%s** has had its premium removed".formatted(guild.getName())).queue(); } } diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/botadmin/premium/SetSubCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/botadmin/premium/SetSubCommand.java index 811a6fc..a034d78 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/botadmin/premium/SetSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/botadmin/premium/SetSubCommand.java @@ -4,6 +4,7 @@ import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.command.CommandInfo; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.premium.PremiumProfile; import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; @@ -23,7 +24,7 @@ public class SetSubCommand extends BatSubCommand { private final GuildService guildService; @Autowired - public SetSubCommand(GuildService guildService) { + public SetSubCommand(@NonNull GuildService guildService) { this.guildService = guildService; super.addOption(OptionType.STRING, "guild", "The guild id to set as premium", true); super.addOption(OptionType.BOOLEAN, "infinite", "Whether the premium length should be infinite", true); @@ -49,13 +50,12 @@ public class SetSubCommand extends BatSubCommand { interaction.reply("The guild with the id %s does not exist".formatted(guildId)).queue(); return; } - BatGuild.Premium premium = batGuild.getPremium(); + PremiumProfile premium = batGuild.getPremiumProfile(); if (!infinite) { premium.addTime(); } else { premium.addInfiniteTime(); } - guildService.saveGuild(batGuild); if (!infinite) { interaction.reply("The guild **%s** has been set as premium until ".formatted(guild.getName(), premium.getExpiresAt().toInstant().toEpochMilli() / 1000)).queue(); } else { diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/server/PremiumCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/server/PremiumCommand.java index 742b92a..d76f2db 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/server/PremiumCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/server/PremiumCommand.java @@ -5,6 +5,7 @@ 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 cc.fascinated.bat.premium.PremiumProfile; import lombok.NonNull; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.Permission; @@ -21,7 +22,7 @@ import org.springframework.stereotype.Component; public class PremiumCommand extends BatCommand { @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { - BatGuild.Premium premium = guild.getPremium(); + PremiumProfile premium = guild.getPremiumProfile(); EmbedBuilder embed = EmbedUtils.genericEmbed().setAuthor("Premium Information"); if (premium.hasPremium()) { embed.addField("Premium", premium.hasPremium() ? "Yes" : "No", true); diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/server/feature/DisableSubCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/server/feature/DisableSubCommand.java index 8aa5248..0982e5b 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/server/feature/DisableSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/server/feature/DisableSubCommand.java @@ -8,7 +8,6 @@ import cc.fascinated.bat.features.base.profile.FeatureProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.FeatureService; -import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; @@ -24,11 +23,8 @@ import org.springframework.stereotype.Component; @Component("feature:disable.sub") @CommandInfo(name = "disable", description = "Disables a feature") public class DisableSubCommand extends BatSubCommand { - private final GuildService guildService; - @Autowired - public DisableSubCommand(@NonNull GuildService guildService) { - this.guildService = guildService; + public DisableSubCommand() { super.addOption(OptionType.STRING, "feature", "The feature to disable", true); } @@ -52,15 +48,14 @@ public class DisableSubCommand extends BatSubCommand { Feature feature = FeatureService.INSTANCE.getFeature(featureName); if (featureProfile.isFeatureDisabled(feature)) { interaction.replyEmbeds(EmbedUtils.errorEmbed() - .setDescription("The feature `%s` is already enabled".formatted(feature.getName())) + .setDescription("The feature `%s` is already disabled".formatted(feature.getName())) .build()).queue(); return; } featureProfile.disableFeature(feature); - guildService.saveGuild(guild); interaction.replyEmbeds(EmbedUtils.successEmbed() - .setDescription("Successfully enabled the `%s` feature".formatted(feature.getName())) + .setDescription("Successfully disabled the `%s` feature".formatted(feature.getName())) .build()).queue(); } } diff --git a/src/main/java/cc/fascinated/bat/features/base/commands/server/feature/EnableSubCommand.java b/src/main/java/cc/fascinated/bat/features/base/commands/server/feature/EnableSubCommand.java index def7690..8e9e860 100644 --- a/src/main/java/cc/fascinated/bat/features/base/commands/server/feature/EnableSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/base/commands/server/feature/EnableSubCommand.java @@ -8,7 +8,6 @@ import cc.fascinated.bat.features.base.profile.FeatureProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.FeatureService; -import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; @@ -24,11 +23,8 @@ import org.springframework.stereotype.Component; @Component("feature:enable.sub") @CommandInfo(name = "enable", description = "Enables a feature") public class EnableSubCommand extends BatSubCommand { - private final GuildService guildService; - @Autowired - public EnableSubCommand(@NonNull GuildService guildService) { - this.guildService = guildService; + public EnableSubCommand() { super.addOption(OptionType.STRING, "feature", "The feature to enable", true); } @@ -58,7 +54,6 @@ public class EnableSubCommand extends BatSubCommand { } featureProfile.enableFeature(feature); - guildService.saveGuild(guild); interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully enabled the `%s` feature".formatted(feature.getName())) .build()).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/base/profile/FeatureProfile.java b/src/main/java/cc/fascinated/bat/features/base/profile/FeatureProfile.java index 7574208..be29cc2 100644 --- a/src/main/java/cc/fascinated/bat/features/base/profile/FeatureProfile.java +++ b/src/main/java/cc/fascinated/bat/features/base/profile/FeatureProfile.java @@ -1,9 +1,12 @@ package cc.fascinated.bat.features.base.profile; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.features.Feature; +import com.google.gson.Gson; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; +import org.bson.Document; import java.util.HashMap; import java.util.Map; @@ -11,7 +14,8 @@ import java.util.Map; /** * @author Fascinated (fascinated7) */ -public class FeatureProfile extends Profile { +@NoArgsConstructor +public class FeatureProfile extends Serializable { private static final FeatureState DEFAULT_STATE = FeatureState.ENABLED; /** @@ -19,19 +23,12 @@ public class FeatureProfile extends Profile { */ private Map featureStates; - public FeatureProfile() { - super("feature"); - } - /** * Gets the feature states * * @return the feature states */ public FeatureState getFeatureState(Feature feature) { - if (this.featureStates == null) { - this.featureStates = new HashMap<>(); - } if (feature == null) { return DEFAULT_STATE; } @@ -85,9 +82,6 @@ public class FeatureProfile extends Profile { * @param state the state to set */ public void setFeatureState(Feature feature, FeatureState state) { - if (this.featureStates == null) { - this.featureStates = new HashMap<>(); - } this.featureStates.put(feature.getName().toUpperCase(), state); } @@ -96,6 +90,23 @@ public class FeatureProfile extends Profile { this.featureStates = null; } + @Override + public void load(Document document, Gson gson) { + this.featureStates = new HashMap<>(); + for (String key : document.keySet()) { + this.featureStates.put(key, FeatureState.valueOf(document.getString(key))); + } + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + for (String key : this.featureStates.keySet()) { + document.put(key, this.featureStates.get(key).name()); + } + return document; + } + @AllArgsConstructor @Getter public enum FeatureState { ENABLED(":white_check_mark:"), @@ -104,6 +115,6 @@ public class FeatureProfile extends Profile { /** * The emoji for the feature state */ - private String emoji; + private final String emoji; } } 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 54cc7b3..8dfb731 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/BirthdayFeature.java @@ -31,9 +31,8 @@ public class BirthdayFeature extends Feature implements EventListener { @Override public void onGuildMemberLeave(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull GuildMemberRemoveEvent event) { - BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); + BirthdayProfile profile = guild.getBirthdayProfile(); profile.removeBirthday(user.getId()); - guildService.saveGuild(guild); } /** @@ -41,8 +40,8 @@ public class BirthdayFeature extends Feature implements EventListener { */ @Scheduled(cron = "0 1 0 * * *") private void checkBirthdays() { - for (BatGuild guild : guildService.getAllGuilds()) { - BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); + for (BatGuild guild : guildService.getGuilds().values()) { + BirthdayProfile profile = guild.getBirthdayProfile(); profile.checkBirthdays(guild); } } 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 ab0d138..ee98957 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/UserBirthday.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/UserBirthday.java @@ -1,9 +1,10 @@ package cc.fascinated.bat.features.birthday; -import lombok.AllArgsConstructor; +import cc.fascinated.bat.common.Serializable; +import com.google.gson.Gson; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; +import org.bson.Document; import java.util.Calendar; import java.util.Date; @@ -11,11 +12,9 @@ import java.util.Date; /** * @author Fascinated (fascinated7) */ -@AllArgsConstructor -@NoArgsConstructor @Getter @Setter -public class UserBirthday { +public class UserBirthday extends Serializable { /** * The user's birthday */ @@ -43,4 +42,23 @@ public class UserBirthday { } return age; } + + @Override + public void load(Document document, Gson gson) { + this.birthday = document.getDate("birthday"); + this.hidden = document.getBoolean("hidden", false); + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + document.put("birthday", this.birthday); + document.put("hidden", this.hidden); + return document; + } + + @Override + public void reset() { + + } } diff --git a/src/main/java/cc/fascinated/bat/features/birthday/command/ChannelSubCommand.java b/src/main/java/cc/fascinated/bat/features/birthday/command/ChannelSubCommand.java index ec3f01b..584c027 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/command/ChannelSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/command/ChannelSubCommand.java @@ -7,7 +7,6 @@ import cc.fascinated.bat.common.TextChannelUtils; 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 lombok.NonNull; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Member; @@ -26,17 +25,14 @@ import org.springframework.stereotype.Component; @Component("birthday:channel.sub") @CommandInfo(name = "channel", description = "Sets the birthday notification channel", requiredPermissions = Permission.MANAGE_SERVER) public class ChannelSubCommand extends BatSubCommand { - private final GuildService guildService; - @Autowired - public ChannelSubCommand(GuildService guildService) { + public ChannelSubCommand() { super.addOption(OptionType.CHANNEL, "channel", "The channel birthdays will be sent in", false); - this.guildService = guildService; } @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { - BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); + BirthdayProfile profile = guild.getBirthdayProfile(); OptionMapping option = interaction.getOption("channel"); if (option == null) { if (!TextChannelUtils.isValidChannel(profile.getChannelId())) { @@ -60,8 +56,6 @@ public class ChannelSubCommand extends BatSubCommand { } profile.setChannelId(targetChannel.getId()); - guildService.saveGuild(guild); - interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully set the birthday channel to %s".formatted(targetChannel.asTextChannel().getAsMention())) .build()).queue(); 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 4963396..e848fae 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 @@ -6,7 +6,6 @@ import cc.fascinated.bat.common.EmbedUtils; 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 lombok.NonNull; import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.Member; @@ -24,17 +23,14 @@ import org.springframework.stereotype.Component; @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 final GuildService guildService; - @Autowired - public MessageSubCommand(GuildService guildService) { + public MessageSubCommand() { super.addOption(OptionType.STRING, "message", "The message that is sent. (Placeholders: {user}, {age})", true); - this.guildService = guildService; } @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { - BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); + BirthdayProfile profile = guild.getBirthdayProfile(); OptionMapping messageOption = interaction.getOption("message"); if (messageOption == null) { interaction.replyEmbeds(EmbedUtils.errorEmbed() @@ -58,7 +54,6 @@ 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(); diff --git a/src/main/java/cc/fascinated/bat/features/birthday/command/PrivateSubCommand.java b/src/main/java/cc/fascinated/bat/features/birthday/command/PrivateSubCommand.java index 58909a5..12ca99f 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/command/PrivateSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/command/PrivateSubCommand.java @@ -7,7 +7,6 @@ import cc.fascinated.bat.features.birthday.UserBirthday; 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 lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; @@ -24,17 +23,14 @@ import org.springframework.stereotype.Component; @Component("birthday:private.sub") @CommandInfo(name = "private", description = "Changes whether your birthday is private or not") public class PrivateSubCommand extends BatSubCommand { - private final GuildService guildService; - @Autowired - public PrivateSubCommand(@NonNull GuildService guildService) { - this.guildService = guildService; + public PrivateSubCommand() { super.addOption(OptionType.BOOLEAN, "enabled", "Whether your birthday is private or not", true); } @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { - BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); + BirthdayProfile profile = guild.getBirthdayProfile(); OptionMapping enabledOption = interaction.getOption("enabled"); if (enabledOption == null) { interaction.replyEmbeds(EmbedUtils.errorEmbed() @@ -53,8 +49,6 @@ public class PrivateSubCommand extends BatSubCommand { } birthday.setHidden(enabled); - guildService.saveGuild(guild); - interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Your birthday privacy settings have been updated\n\n**Private:** " + (enabled ? "Yes" : "No")) .build()).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/birthday/command/RemoveSubCommand.java b/src/main/java/cc/fascinated/bat/features/birthday/command/RemoveSubCommand.java index 94582e3..12246c3 100644 --- a/src/main/java/cc/fascinated/bat/features/birthday/command/RemoveSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/birthday/command/RemoveSubCommand.java @@ -6,12 +6,10 @@ import cc.fascinated.bat.common.EmbedUtils; 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 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.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -21,20 +19,11 @@ import org.springframework.stereotype.Component; @Component("birthday:remove.sub") @CommandInfo(name = "remove", description = "Remove your birthday from this guild") public class RemoveSubCommand extends BatSubCommand { - private final GuildService guildService; - - @Autowired - public RemoveSubCommand(GuildService guildService) { - this.guildService = guildService; - } - @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { - BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); + BirthdayProfile profile = guild.getBirthdayProfile(); profile.removeBirthday(user.getId()); - guildService.saveGuild(guild); - interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Your birthday has been removed from this guild") .build()).queue(); 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 d6eb6ca..8edab74 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 @@ -7,7 +7,6 @@ import cc.fascinated.bat.features.birthday.UserBirthday; 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 lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; @@ -29,17 +28,15 @@ import java.util.Date; @CommandInfo(name = "set", description = "Add your birthday to this guild") public class SetSubCommand extends BatSubCommand { private static final SimpleDateFormat FORMATTER = new SimpleDateFormat("dd/MM/yyyy"); - private final GuildService guildService; @Autowired - public SetSubCommand(GuildService guildService) { + public SetSubCommand() { super.addOption(OptionType.STRING, "birthday", "Your birthday (format: DAY/MONTH/YEAR - 01/05/2004)", true); - this.guildService = guildService; } @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { - BirthdayProfile profile = guild.getProfile(BirthdayProfile.class); + BirthdayProfile profile = guild.getBirthdayProfile(); if (!profile.hasChannelSetup()) { interaction.replyEmbeds(EmbedUtils.errorEmbed() .setDescription("Birthdays have not been enabled in this guild. Please ask an administrator to enable them.") @@ -66,9 +63,10 @@ public class SetSubCommand extends BatSubCommand { return; } - profile.addBirthday(member.getId(), new UserBirthday(birthday, false)); - guildService.saveGuild(guild); - + UserBirthday userBirthday = new UserBirthday(); + userBirthday.setBirthday(birthday); + userBirthday.setHidden(false); + profile.addBirthday(member.getId(), userBirthday); interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("You have updated your birthday!") .build()).queue(); 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 3e0a945..eb68c0f 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 @@ -34,7 +34,7 @@ public class ViewSubCommand 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); + BirthdayProfile profile = guild.getBirthdayProfile(); 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/profile/BirthdayProfile.java b/src/main/java/cc/fascinated/bat/features/birthday/profile/BirthdayProfile.java index 5f72745..f655610 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 @@ -1,14 +1,17 @@ package cc.fascinated.bat.features.birthday.profile; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.features.birthday.UserBirthday; import cc.fascinated.bat.model.BatGuild; +import com.google.gson.Gson; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import org.bson.Document; import java.util.*; @@ -17,7 +20,8 @@ import java.util.*; */ @Getter @Setter -public class BirthdayProfile extends Profile { +@NoArgsConstructor +public class BirthdayProfile extends Serializable { private static final String DEFAULT_MESSAGE = "Happy Birthday {user} :tada: :birthday: You are now {age} years old!"; /** @@ -35,10 +39,6 @@ public class BirthdayProfile extends Profile { */ private String message = DEFAULT_MESSAGE; - public BirthdayProfile() { - super("birthday"); - } - /** * Adds a birthday to be tracked * @@ -202,4 +202,27 @@ public class BirthdayProfile extends Profile { birthdays.clear(); channelId = null; } + + @Override + public void load(Document document, Gson gson) { + birthdays = new HashMap<>(); + for (String key : document.keySet()) { + UserBirthday userBirthday = new UserBirthday(); + userBirthday.load((Document) document.get(key), gson); + birthdays.put(key, userBirthday); + } + channelId = document.getString("channelId"); + message = (String) document.getOrDefault("message", DEFAULT_MESSAGE); + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + for (String key : birthdays.keySet()) { + document.put(key, birthdays.get(key).serialize(gson)); + } + document.put("channelId", channelId); + document.put("message", message); + return document; + } } diff --git a/src/main/java/cc/fascinated/bat/features/namehistory/NameHistoryListener.java b/src/main/java/cc/fascinated/bat/features/namehistory/NameHistoryListener.java index d7a66da..ac5dedd 100644 --- a/src/main/java/cc/fascinated/bat/features/namehistory/NameHistoryListener.java +++ b/src/main/java/cc/fascinated/bat/features/namehistory/NameHistoryListener.java @@ -6,7 +6,6 @@ import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.FeatureService; import cc.fascinated.bat.service.GuildService; -import cc.fascinated.bat.service.UserService; import lombok.NonNull; import net.dv8tion.jda.api.events.guild.member.update.GuildMemberUpdateNicknameEvent; import net.dv8tion.jda.api.events.user.update.UserUpdateGlobalNameEvent; @@ -18,13 +17,11 @@ import org.springframework.stereotype.Component; */ @Component public class NameHistoryListener implements EventListener { - private final UserService userService; private final GuildService guildService; private final FeatureService featureService; @Autowired - public NameHistoryListener(@NonNull UserService userService, @NonNull GuildService guildService, @NonNull FeatureService featureService) { - this.userService = userService; + public NameHistoryListener(@NonNull GuildService guildService, @NonNull FeatureService featureService) { this.guildService = guildService; this.featureService = featureService; } @@ -33,7 +30,6 @@ public class NameHistoryListener implements EventListener { public void onUserUpdateGlobalName(@NonNull BatUser user, String oldName, String newName, @NonNull UserUpdateGlobalNameEvent event) { NameHistoryProfile profile = user.getNameHistoryProfile(); profile.addName(newName); - userService.saveUser(user); } @Override @@ -46,6 +42,5 @@ public class NameHistoryListener implements EventListener { cc.fascinated.bat.features.namehistory.profile.guild.NameHistoryProfile profile = guild.getNameHistoryProfile(); profile.addName(user, newName); - guildService.saveGuild(guild); } } diff --git a/src/main/java/cc/fascinated/bat/features/namehistory/TrackedName.java b/src/main/java/cc/fascinated/bat/features/namehistory/TrackedName.java index b30728c..e6e0769 100644 --- a/src/main/java/cc/fascinated/bat/features/namehistory/TrackedName.java +++ b/src/main/java/cc/fascinated/bat/features/namehistory/TrackedName.java @@ -1,22 +1,42 @@ package cc.fascinated.bat.features.namehistory; -import lombok.AllArgsConstructor; +import cc.fascinated.bat.common.Serializable; +import com.google.gson.Gson; import lombok.Getter; +import lombok.Setter; +import org.bson.Document; import java.util.Date; /** * @author Fascinated (fascinated7) */ -@AllArgsConstructor @Getter -public class TrackedName { +@Getter @Setter +public class TrackedName extends Serializable { /** * The new name of the user */ - private final String name; + private String name; /** * The date the name was changed */ - private final Date changedDate; + private Date changedDate; + + @Override + public void load(Document document, Gson gson) { + this.name = document.getString("name"); + this.changedDate = document.getDate("changedDate"); + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + document.put("name", this.name); + document.put("changedDate", this.changedDate); + return document; + } + + @Override + public void reset() {} } diff --git a/src/main/java/cc/fascinated/bat/features/namehistory/profile/guild/NameHistoryProfile.java b/src/main/java/cc/fascinated/bat/features/namehistory/profile/guild/NameHistoryProfile.java index 01e0df9..8314766 100644 --- a/src/main/java/cc/fascinated/bat/features/namehistory/profile/guild/NameHistoryProfile.java +++ b/src/main/java/cc/fascinated/bat/features/namehistory/profile/guild/NameHistoryProfile.java @@ -1,22 +1,25 @@ package cc.fascinated.bat.features.namehistory.profile.guild; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.features.namehistory.NameHistoryFeature; import cc.fascinated.bat.features.namehistory.TrackedName; import cc.fascinated.bat.model.BatUser; +import com.google.gson.Gson; +import lombok.NoArgsConstructor; +import org.bson.Document; import java.util.*; /** * @author Fascinated (fascinated7) */ -public class NameHistoryProfile extends Profile { +@NoArgsConstructor +public class NameHistoryProfile extends Serializable { + /** + * The name history of the user + */ private Map> nameHistory; - public NameHistoryProfile() { - super("name-history"); - } - /** * Gets the name history of the user * @@ -50,7 +53,10 @@ public class NameHistoryProfile extends Profile { * @param name the name to add */ public void addName(BatUser user, String name) { - getNameHistory(user).add(new TrackedName(name, new Date())); + TrackedName trackedName = new TrackedName(); + trackedName.setName(name); + trackedName.setChangedDate(new Date()); + getNameHistory(user).add(trackedName); cleanup(); } @@ -75,4 +81,31 @@ public class NameHistoryProfile extends Profile { public void reset() { this.nameHistory = null; } + + @Override + public void load(Document document, Gson gson) { + this.nameHistory = new HashMap<>(); + for (String key : document.keySet()) { + List trackedNames = new LinkedList<>(); + for (Document trackedNameDocument : (List) document.get(key)) { + TrackedName trackedName = new TrackedName(); + trackedName.load(trackedNameDocument, gson); + trackedNames.add(trackedName); + } + this.nameHistory.put(key, trackedNames); + } + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + for (String key : this.nameHistory.keySet()) { + List trackedNames = new LinkedList<>(); + for (TrackedName trackedName : this.nameHistory.get(key)) { + trackedNames.add(trackedName.serialize(gson)); + } + document.put(key, trackedNames); + } + return document; + } } diff --git a/src/main/java/cc/fascinated/bat/features/namehistory/profile/user/NameHistoryProfile.java b/src/main/java/cc/fascinated/bat/features/namehistory/profile/user/NameHistoryProfile.java index 2048a10..e2f69a2 100644 --- a/src/main/java/cc/fascinated/bat/features/namehistory/profile/user/NameHistoryProfile.java +++ b/src/main/java/cc/fascinated/bat/features/namehistory/profile/user/NameHistoryProfile.java @@ -1,8 +1,11 @@ package cc.fascinated.bat.features.namehistory.profile.user; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.features.namehistory.NameHistoryFeature; import cc.fascinated.bat.features.namehistory.TrackedName; +import com.google.gson.Gson; +import lombok.NoArgsConstructor; +import org.bson.Document; import java.util.ArrayList; import java.util.Date; @@ -12,13 +15,13 @@ import java.util.List; /** * @author Fascinated (fascinated7) */ -public class NameHistoryProfile extends Profile { +@NoArgsConstructor +public class NameHistoryProfile extends Serializable { + /** + * The name history of the user + */ private List nameHistory; - public NameHistoryProfile() { - super("name-history"); - } - /** * Gets the name history of the user * @@ -49,7 +52,10 @@ public class NameHistoryProfile extends Profile { if (this.nameHistory == null) { this.nameHistory = new LinkedList<>(); } - this.nameHistory.add(new TrackedName(name, new Date())); + TrackedName trackedName = new TrackedName(); + trackedName.setName(name); + trackedName.setChangedDate(new Date()); + this.nameHistory.add(trackedName); cleanup(); } @@ -72,4 +78,29 @@ public class NameHistoryProfile extends Profile { public void reset() { this.nameHistory = null; } + + @Override + public void load(Document document, Gson gson) { + this.nameHistory = new LinkedList<>(); + for (Document trackedNameDocument : document.getList("nameHistory", Document.class)) { + TrackedName trackedName = new TrackedName(); + trackedName.load(trackedNameDocument, gson); + + this.nameHistory.add(trackedName); + } + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + List trackedNames = new ArrayList<>(); + for (TrackedName trackedName : this.nameHistory) { + Document trackedNameDocument = new Document(); + trackedNameDocument.put("name", trackedName.getName()); + trackedNameDocument.put("changedDate", trackedName.getChangedDate()); + trackedNames.add(trackedNameDocument); + } + document.put("nameHistory", trackedNames); + return document; + } } diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java b/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java index 7bb16a3..f1ece1f 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java @@ -67,7 +67,6 @@ public class NumberOneScoreFeedListener implements EventListener { if (channel == null) { log.error("Scoresaber user feed channel is null for guild {}, removing the stored channel.", guild.getId()); profile.setChannelId(null); - guildService.saveGuild(batGuild); continue; } channel.sendMessageEmbeds(ScoreSaberFeature.buildScoreEmbed(score)).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/UserScoreFeedListener.java b/src/main/java/cc/fascinated/bat/features/scoresaber/UserScoreFeedListener.java index 826c352..c95b8f8 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/UserScoreFeedListener.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/UserScoreFeedListener.java @@ -53,7 +53,6 @@ public class UserScoreFeedListener implements EventListener { if (channel == null) { log.error("Scoresaber user feed channel is null for guild {}, removing the stored channel.", guild.getId()); profile.setChannelId(null); - guildService.saveGuild(batGuild); continue; } channel.sendMessageEmbeds(ScoreSaberFeature.buildScoreEmbed(score)).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ChannelSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ChannelSubCommand.java index 64d6a07..b11ae85 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ChannelSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ChannelSubCommand.java @@ -7,7 +7,6 @@ import cc.fascinated.bat.common.TextChannelUtils; import cc.fascinated.bat.features.scoresaber.profile.guild.NumberOneScoreFeedProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.ChannelType; @@ -25,12 +24,9 @@ import org.springframework.stereotype.Component; @Component("scoresaber-number-one-feed:channel.sub") @CommandInfo(name = "channel", description = "Sets the feed channel") public class ChannelSubCommand extends BatSubCommand { - private final GuildService guildService; - @Autowired - public ChannelSubCommand(GuildService guildService) { + public ChannelSubCommand() { super.addOption(OptionType.CHANNEL, "channel", "The channel scores are sent in", false); - this.guildService = guildService; } @Override @@ -59,8 +55,6 @@ public class ChannelSubCommand extends BatSubCommand { } profile.setChannelId(targetChannel.getId()); - guildService.saveGuild(guild); - interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully set the feed channel to %s".formatted(targetChannel.asTextChannel().getAsMention())) .build()).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ResetSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ResetSubCommand.java index 1018e37..0ea1c1a 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ResetSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ResetSubCommand.java @@ -6,12 +6,10 @@ import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.scoresaber.profile.guild.NumberOneScoreFeedProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.GuildService; 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.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -20,18 +18,10 @@ import org.springframework.stereotype.Component; @Component("scoresaber-number-one-feed:reset.sub") @CommandInfo(name = "reset", description = "Resets the settings") public class ResetSubCommand extends BatSubCommand { - private final GuildService guildService; - - @Autowired - public ResetSubCommand(GuildService guildService) { - this.guildService = guildService; - } - @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { NumberOneScoreFeedProfile profile = guild.getProfile(NumberOneScoreFeedProfile.class); profile.reset(); - guildService.saveGuild(guild); interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully reset the settings.") diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/LinkSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/LinkSubCommand.java index 0edf638..1c5d0bc 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/LinkSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/LinkSubCommand.java @@ -7,7 +7,6 @@ import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.model.token.beatsaber.scoresaber.ScoreSaberAccountToken; import cc.fascinated.bat.service.ScoreSaberService; -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,13 +23,11 @@ import org.springframework.stereotype.Component; @CommandInfo(name = "link", description = "Links your ScoreSaber profile") public class LinkSubCommand extends BatSubCommand { private final ScoreSaberService scoreSaberService; - private final UserService userService; @Autowired - public LinkSubCommand(@NonNull ScoreSaberService scoreSaberService, @NonNull UserService userService) { + public LinkSubCommand(@NonNull ScoreSaberService scoreSaberService) { super.addOption(OptionType.STRING, "link", "Link your ScoreSaber profile", true); this.scoreSaberService = scoreSaberService; - this.userService = userService; } @Override @@ -65,7 +62,6 @@ public class LinkSubCommand extends BatSubCommand { } user.getScoreSaberProfile().setAccountId(id); - userService.saveUser(user); interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully linked your [ScoreSaber](%s) profile".formatted("https://scoresaber.com/u/%s".formatted(id))) .build()).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ResetSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ResetSubCommand.java index 3aef5c8..d655e98 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ResetSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ResetSubCommand.java @@ -6,12 +6,10 @@ import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.scoresaber.profile.user.ScoreSaberProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -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; import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -20,18 +18,10 @@ import org.springframework.stereotype.Component; @Component("scoresaber:reset.sub") @CommandInfo(name = "reset", description = "Reset your settings") public class ResetSubCommand extends BatSubCommand { - private final UserService userService; - - @Autowired - public ResetSubCommand(@NonNull UserService userService) { - this.userService = userService; - } - @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { ScoreSaberProfile profile = user.getScoreSaberProfile(); profile.reset(); - userService.saveUser(user); interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully reset your settings.") diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ChannelSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ChannelSubCommand.java index 081dc01..4566791 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ChannelSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ChannelSubCommand.java @@ -7,7 +7,6 @@ import cc.fascinated.bat.common.TextChannelUtils; import cc.fascinated.bat.features.scoresaber.profile.guild.UserScoreFeedProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.ChannelType; @@ -25,12 +24,9 @@ import org.springframework.stereotype.Component; @Component("scoresaber-user-feed:channel.sub") @CommandInfo(name = "channel", description = "Sets the feed channel") public class ChannelSubCommand extends BatSubCommand { - private final GuildService guildService; - @Autowired - public ChannelSubCommand(GuildService guildService) { + public ChannelSubCommand() { super.addOption(OptionType.CHANNEL, "channel", "The channel scores are sent in", false); - this.guildService = guildService; } @Override @@ -59,8 +55,6 @@ public class ChannelSubCommand extends BatSubCommand { } profile.setChannelId(targetChannel.getId()); - guildService.saveGuild(guild); - interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully set the feed channel to %s".formatted(targetChannel.asTextChannel().getAsMention())) .build()).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ResetSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ResetSubCommand.java index 30b6c5c..fd39d1d 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ResetSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ResetSubCommand.java @@ -6,12 +6,10 @@ import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.features.scoresaber.profile.guild.UserScoreFeedProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.GuildService; 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.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -20,19 +18,10 @@ import org.springframework.stereotype.Component; @Component("scoresaber-user-feed:reset.sub") @CommandInfo(name = "reset", description = "Resets the settings") public class ResetSubCommand extends BatSubCommand { - private final GuildService guildService; - - @Autowired - public ResetSubCommand(GuildService guildService) { - this.guildService = guildService; - } - @Override public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { UserScoreFeedProfile profile = guild.getProfile(UserScoreFeedProfile.class); profile.reset(); - guildService.saveGuild(guild); - interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("Successfully reset the settings.") .build()).queue(); diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/UserSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/UserSubCommand.java index d0f12ed..02579a2 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/UserSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/UserSubCommand.java @@ -83,6 +83,5 @@ public class UserSubCommand extends BatSubCommand { target.getAsMention() )) .build()).queue(); - guildService.saveGuild(guild); } } diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/profile/guild/NumberOneScoreFeedProfile.java b/src/main/java/cc/fascinated/bat/features/scoresaber/profile/guild/NumberOneScoreFeedProfile.java index a035938..0d70ea0 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/profile/guild/NumberOneScoreFeedProfile.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/profile/guild/NumberOneScoreFeedProfile.java @@ -1,26 +1,26 @@ package cc.fascinated.bat.features.scoresaber.profile.guild; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.service.DiscordService; +import com.google.gson.Gson; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import org.bson.Document; /** * @author Fascinated (fascinated7) */ @Getter @Setter -public class NumberOneScoreFeedProfile extends Profile { +@NoArgsConstructor +public class NumberOneScoreFeedProfile extends Serializable { /** * The channel ID of the score feed */ private String channelId; - public NumberOneScoreFeedProfile() { - super("scoresaber-number-one-score-feed"); - } - /** * Gets the channel as a TextChannel * @@ -34,4 +34,16 @@ public class NumberOneScoreFeedProfile extends Profile { public void reset() { this.channelId = null; } + + @Override + public void load(Document document, Gson gson) { + this.channelId = document.getString("channelId"); + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + document.put("channelId", this.channelId); + return document; + } } diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/profile/guild/UserScoreFeedProfile.java b/src/main/java/cc/fascinated/bat/features/scoresaber/profile/guild/UserScoreFeedProfile.java index dcee80c..d88e50c 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/profile/guild/UserScoreFeedProfile.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/profile/guild/UserScoreFeedProfile.java @@ -1,10 +1,13 @@ package cc.fascinated.bat.features.scoresaber.profile.guild; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.service.DiscordService; +import com.google.gson.Gson; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import org.bson.Document; import java.util.ArrayList; import java.util.List; @@ -14,7 +17,8 @@ import java.util.List; */ @Getter @Setter -public class UserScoreFeedProfile extends Profile { +@NoArgsConstructor +public class UserScoreFeedProfile extends Serializable { /** * The channel ID of the score feed */ @@ -25,10 +29,6 @@ public class UserScoreFeedProfile extends Profile { */ private List trackedUsers; - public UserScoreFeedProfile() { - super("scoresaber-user-score-feed"); - } - /** * Gets the tracked users * @@ -92,4 +92,18 @@ public class UserScoreFeedProfile extends Profile { this.channelId = null; this.trackedUsers = null; } + + @Override + public void load(Document document, Gson gson) { + this.channelId = document.getString("channelId"); + this.trackedUsers = document.getList("trackedUsers", String.class, new ArrayList<>()); + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + document.put("channelId", this.channelId); + document.put("trackedUsers", this.trackedUsers); + return document; + } } diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/profile/user/ScoreSaberProfile.java b/src/main/java/cc/fascinated/bat/features/scoresaber/profile/user/ScoreSaberProfile.java index ce91d3d..5a5cfbd 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/profile/user/ScoreSaberProfile.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/profile/user/ScoreSaberProfile.java @@ -1,26 +1,38 @@ package cc.fascinated.bat.features.scoresaber.profile.user; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; +import com.google.gson.Gson; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; +import org.bson.Document; /** * @author Fascinated (fascinated7) */ @Setter @Getter -public class ScoreSaberProfile extends Profile { +@NoArgsConstructor +public class ScoreSaberProfile extends Serializable { /** * The Account ID of the ScoreSaber profile */ private String accountId; - public ScoreSaberProfile() { - super("scoresaber"); - } - @Override public void reset() { this.accountId = null; } + + @Override + public void load(Document document, Gson gson) { + this.accountId = document.getString("accountId"); + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + document.put("accountId", this.accountId); + return document; + } } diff --git a/src/main/java/cc/fascinated/bat/features/spotify/command/UnlinkSubCommand.java b/src/main/java/cc/fascinated/bat/features/spotify/command/UnlinkSubCommand.java index 28dd2ab..cfd99ae 100644 --- a/src/main/java/cc/fascinated/bat/features/spotify/command/UnlinkSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/spotify/command/UnlinkSubCommand.java @@ -9,13 +9,11 @@ import cc.fascinated.bat.exception.BatException; import cc.fascinated.bat.features.spotify.profile.SpotifyProfile; import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.service.UserService; import lombok.NonNull; import lombok.SneakyThrows; 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.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -24,13 +22,6 @@ import org.springframework.stereotype.Component; @Component @CommandInfo(name = "unlink", description = "Unlink your Spotify account") public class UnlinkSubCommand extends BatSubCommand implements EventListener { - private final UserService userService; - - @Autowired - public UnlinkSubCommand(@NonNull UserService userService) { - this.userService = userService; - } - @Override @SneakyThrows public void execute(BatGuild guild, @NonNull BatUser user, @NonNull MessageChannel channel, Member member, @NonNull SlashCommandInteraction interaction) { SpotifyProfile profile = user.getProfile(SpotifyProfile.class); @@ -39,7 +30,6 @@ public class UnlinkSubCommand extends BatSubCommand implements EventListener { } profile.reset(); - userService.saveUser(user); interaction.replyEmbeds(EmbedUtils.successEmbed() .setDescription("%s Successfully unlinked your Spotify account.".formatted(Emojis.CHECK_MARK_EMOJI)) .build()) diff --git a/src/main/java/cc/fascinated/bat/features/spotify/profile/SpotifyProfile.java b/src/main/java/cc/fascinated/bat/features/spotify/profile/SpotifyProfile.java index eebb3d8..319279d 100644 --- a/src/main/java/cc/fascinated/bat/features/spotify/profile/SpotifyProfile.java +++ b/src/main/java/cc/fascinated/bat/features/spotify/profile/SpotifyProfile.java @@ -1,14 +1,16 @@ package cc.fascinated.bat.features.spotify.profile; -import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.common.Serializable; +import com.google.gson.Gson; import lombok.Getter; import lombok.Setter; +import org.bson.Document; /** * @author Fascinated (fascinated7) */ @Getter @Setter -public class SpotifyProfile extends Profile { +public class SpotifyProfile extends Serializable { /** * The access token */ @@ -24,10 +26,6 @@ public class SpotifyProfile extends Profile { */ private Long expiresAt; - public SpotifyProfile() { - super("spotify"); - } - /** * Checks if the account has a linked account * @@ -42,4 +40,20 @@ public class SpotifyProfile extends Profile { this.accessToken = null; this.refreshToken = null; } + + @Override + public void load(Document document, Gson gson) { + this.accessToken = document.getString("accessToken"); + this.refreshToken = document.getString("refreshToken"); + this.expiresAt = document.getLong("expiresAt"); + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + document.put("accessToken", this.accessToken); + document.put("refreshToken", this.refreshToken); + document.put("expiresAt", this.expiresAt); + return document; + } } diff --git a/src/main/java/cc/fascinated/bat/migrations/changelogs/BirthdayProfileChangelog.java b/src/main/java/cc/fascinated/bat/migrations/changelogs/BirthdayProfileChangelog.java deleted file mode 100644 index 77f2d99..0000000 --- a/src/main/java/cc/fascinated/bat/migrations/changelogs/BirthdayProfileChangelog.java +++ /dev/null @@ -1,44 +0,0 @@ -package cc.fascinated.bat.migrations.changelogs; - -import com.mongodb.client.FindIterable; -import io.mongock.api.annotations.ChangeUnit; -import io.mongock.api.annotations.Execution; -import io.mongock.api.annotations.RollbackExecution; -import org.bson.Document; -import org.springframework.data.mongodb.core.MongoTemplate; - -/** - * @author Fascinated (fascinated7) - */ -@ChangeUnit(id="birthday-changelog", order = "001", author = "fascinated7") -public class BirthdayProfileChangelog { - private final MongoTemplate mongoTemplate; - - public BirthdayProfileChangelog(MongoTemplate mongoTemplate) { - this.mongoTemplate = mongoTemplate; - } - - @Execution - public void changeSet() { - FindIterable guilds = mongoTemplate.getCollection("guilds").find(); - guilds.forEach(guild -> { - Document profiles = guild.get("profiles", Document.class); - if (profiles == null) { - return; - } - Document birthdayProfile = profiles.get("birthday", Document.class); - if (birthdayProfile == null) { - return; - } - birthdayProfile.remove("birthdays"); - profiles.put("birthday", birthdayProfile); - guild.put("profiles", profiles); - mongoTemplate.getCollection("guilds").replaceOne(new Document("_id", guild.get("_id")), guild); - }); - } - - @RollbackExecution - public void rollback() { - // DO NOTHING - } -} \ No newline at end of file diff --git a/src/main/java/cc/fascinated/bat/migrations/changelogs/ScoresaberProfileRenamePackageChangelog.java b/src/main/java/cc/fascinated/bat/migrations/changelogs/ScoresaberProfileRenamePackageChangelog.java deleted file mode 100644 index eeec163..0000000 --- a/src/main/java/cc/fascinated/bat/migrations/changelogs/ScoresaberProfileRenamePackageChangelog.java +++ /dev/null @@ -1,86 +0,0 @@ -package cc.fascinated.bat.migrations.changelogs; - -import com.mongodb.client.FindIterable; -import io.mongock.api.annotations.ChangeUnit; -import io.mongock.api.annotations.Execution; -import io.mongock.api.annotations.RollbackExecution; -import org.bson.Document; -import org.springframework.data.mongodb.core.MongoTemplate; - -/** - * @author Fascinated (fascinated7) - */ -@ChangeUnit(id = "scoresaber-profile-rename-package-changelog", order = "001", author = "fascinated7") -public class ScoresaberProfileRenamePackageChangelog { - private final MongoTemplate mongoTemplate; - - public ScoresaberProfileRenamePackageChangelog(MongoTemplate mongoTemplate) { - this.mongoTemplate = mongoTemplate; - } - - @Execution - public void changeSet() { - FindIterable guilds = mongoTemplate.getCollection("guilds").find(); - guilds.forEach(guild -> { - Document profiles = guild.get("profiles", Document.class); - if (profiles == null) { - return; - } - - // NumberOneScoreFeedProfile - Document numberOneScoreFeedProfile = profiles.get("scoresaber-number-one-score-feed", Document.class); - if (numberOneScoreFeedProfile == null) { - return; - } - numberOneScoreFeedProfile.put("_class", "cc.fascinated.bat.features.scoresaber.profile.guild.NumberOneScoreFeedProfile"); - profiles.put("scoresaber-number-one-score-feed", numberOneScoreFeedProfile); - - guild.put("profiles", profiles); - mongoTemplate.getCollection("guilds").replaceOne(new Document("_id", guild.get("_id")), guild); - }); - - guilds.forEach(guild -> { - Document profiles = guild.get("profiles", Document.class); - if (profiles == null) { - return; - } - - // UserScoreFeedProfile - Document userScoreFeedProfile = profiles.get("scoresaber-number-one-score-feed", Document.class); - if (userScoreFeedProfile == null) { - return; - } - - userScoreFeedProfile.put("_class", "cc.fascinated.bat.features.scoresaber.profile.guild.UserScoreFeedProfile"); - profiles.put("scoresaber-user-score-feed", userScoreFeedProfile); - - guild.put("profiles", profiles); - mongoTemplate.getCollection("guilds").replaceOne(new Document("_id", guild.get("_id")), guild); - }); - - FindIterable users = mongoTemplate.getCollection("users").find(); - users.forEach(guild -> { - Document profiles = guild.get("profiles", Document.class); - if (profiles == null) { - return; - } - - // ScoreSaberProfile - Document userScoreFeedProfile = profiles.get("scoresaber", Document.class); - if (userScoreFeedProfile == null) { - return; - } - - userScoreFeedProfile.put("_class", "cc.fascinated.bat.features.scoresaber.profile.user.ScoreSaberProfile"); - profiles.put("scoresaber", userScoreFeedProfile); - - guild.put("profiles", profiles); - mongoTemplate.getCollection("users").replaceOne(new Document("_id", guild.get("_id")), guild); - }); - } - - @RollbackExecution - public void rollback() { - // DO NOTHING - } -} \ 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 e6713db..a61c674 100644 --- a/src/main/java/cc/fascinated/bat/model/BatGuild.java +++ b/src/main/java/cc/fascinated/bat/model/BatGuild.java @@ -1,25 +1,41 @@ package cc.fascinated.bat.model; +import cc.fascinated.bat.BatApplication; import cc.fascinated.bat.common.ProfileHolder; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.features.base.profile.FeatureProfile; +import cc.fascinated.bat.features.birthday.profile.BirthdayProfile; import cc.fascinated.bat.features.namehistory.profile.guild.NameHistoryProfile; +import cc.fascinated.bat.premium.PremiumProfile; import cc.fascinated.bat.service.DiscordService; -import lombok.*; +import cc.fascinated.bat.service.MongoService; +import com.mongodb.client.model.ReplaceOptions; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; 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.Calendar; import java.util.Date; +import java.util.HashMap; +import java.util.Map; /** * @author Fascinated (fascinated7) */ -@RequiredArgsConstructor @Getter @Setter @Document(collection = "guilds") public class BatGuild extends ProfileHolder { + private static final Logger log = LoggerFactory.getLogger(BatGuild.class); + /** + * The document that belongs to this guild + */ + private final org.bson.Document document; + /** * The ID of the guild */ @@ -30,23 +46,13 @@ public class BatGuild extends ProfileHolder { /** * The time this guild was joined */ - private Date createdAt = new Date(); + private Date createdAt; - /** - * The premium information for the guild - */ - private Premium premium; - - /** - * The premium information for the guild - * - * @return the premium information - */ - public Premium getPremium() { - if (this.premium == null) { - this.premium = new Premium(null, null, null); - } - return this.premium; + 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"); } /** @@ -85,91 +91,46 @@ public class BatGuild extends ProfileHolder { return getProfile(FeatureProfile.class); } - @AllArgsConstructor - @Getter - @Setter - public static class Premium { - /** - * The time the premium was activated - */ - private Date activatedAt; + /** + * Gets the premium profile + * + * @return the premium profile + */ + public PremiumProfile getPremiumProfile() { + return getProfile(PremiumProfile.class); + } - /** - * The time the premium expires - */ - private Date expiresAt; + /** + * Gets the birthday profile + * + * @return the birthday profile + */ + public BirthdayProfile getBirthdayProfile() { + return getProfile(BirthdayProfile.class); + } - /** - * The type of premium - */ - private Type type; + /** + * Saves the user + */ + public void save() { + document.put("_id", id); + document.put("createdAt", createdAt); - /** - * Checks if the guild has premium - * - * @return whether the guild has premium - */ - public boolean hasPremium() { - return this.type == Type.INFINITE || (this.expiresAt != null && this.expiresAt.after(new Date())); + Map profileDocuments = new HashMap<>(); + for (Serializable profile : getProfiles().values()) { + profileDocuments.put(profile.getClass().getSimpleName(), profile.serialize(BatApplication.GSON)); } + document.put("profiles", profileDocuments); - /** - * Adds a month to the premium time - */ - public void addTime(int months) { - if (this.type == null) { // If the type is null, set it to monthly - this.type = Type.MONTHLY; - } - if (this.expiresAt == null) { - this.expiresAt = new Date(); - } - Calendar calendar = Calendar.getInstance(); - calendar.setTime(new Date()); - calendar.add(Calendar.MONTH, months); - this.expiresAt = calendar.getTime(); - this.type = Type.MONTHLY; - } + MongoService.INSTANCE.getGuildsCollection().replaceOne( + new org.bson.Document("_id", id), + this.getDocument(), + new ReplaceOptions().upsert(true) + ); + } - /** - * Adds a month to the premium time - */ - public void addTime() { - addTime(1); - } - - /** - * Adds infinite time to the premium - */ - public void addInfiniteTime() { - this.type = Type.INFINITE; - this.expiresAt = null; - this.activatedAt = new Date(); - } - - /** - * Removes the premium from the guild - */ - public void removePremium() { - this.activatedAt = null; - this.expiresAt = null; - this.type = null; - } - - /** - * Checks if the premium is infinite - * - * @return whether the premium is infinite - */ - public boolean isInfinite() { - return this.type == Type.INFINITE; - } - - /** - * The premium type for the guild - */ - public enum Type { - INFINITE, - MONTHLY - } + @Override + public T getProfile(Class clazz) { + return getProfileFromDocument(clazz, document); } } diff --git a/src/main/java/cc/fascinated/bat/model/BatUser.java b/src/main/java/cc/fascinated/bat/model/BatUser.java index 830b6ee..11bcfb9 100644 --- a/src/main/java/cc/fascinated/bat/model/BatUser.java +++ b/src/main/java/cc/fascinated/bat/model/BatUser.java @@ -1,18 +1,26 @@ package cc.fascinated.bat.model; +import cc.fascinated.bat.BatApplication; import cc.fascinated.bat.common.ProfileHolder; +import cc.fascinated.bat.common.Serializable; import cc.fascinated.bat.features.namehistory.profile.user.NameHistoryProfile; import cc.fascinated.bat.features.scoresaber.profile.user.ScoreSaberProfile; import cc.fascinated.bat.service.DiscordService; +import cc.fascinated.bat.service.MongoService; +import com.mongodb.client.model.ReplaceOptions; import lombok.Getter; 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; +import java.util.Map; /** * @author Fascinated (fascinated7) @@ -22,6 +30,12 @@ import java.util.Date; @Setter @Document(collection = "users") public class BatUser extends ProfileHolder { + private static final Logger log = LoggerFactory.getLogger(BatUser.class); + /** + * The document that belongs to this user + */ + private final org.bson.Document document; + /** * The ID of the user */ @@ -32,7 +46,14 @@ public class BatUser extends ProfileHolder { /** * The time this user was created */ - private Date createdAt = new Date(); + private Date createdAt; + + public BatUser(@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"); + } /** * The name of the user @@ -67,4 +88,29 @@ public class BatUser extends ProfileHolder { public NameHistoryProfile getNameHistoryProfile() { return getProfile(NameHistoryProfile.class); } + + /** + * Saves the user + */ + public void save() { + document.put("_id", id); + document.put("createdAt", createdAt); + + Map profileDocuments = new HashMap<>(); + for (Serializable profile : getProfiles().values()) { + profileDocuments.put(profile.getClass().getSimpleName(), profile.serialize(BatApplication.GSON)); + } + document.put("profiles", profileDocuments); + + MongoService.INSTANCE.getUsersCollection().replaceOne( + new org.bson.Document("_id", id), + this.getDocument(), + new ReplaceOptions().upsert(true) + ); + } + + @Override + public T getProfile(Class clazz) { + return getProfileFromDocument(clazz, document); + } } diff --git a/src/main/java/cc/fascinated/bat/premium/PremiumProfile.java b/src/main/java/cc/fascinated/bat/premium/PremiumProfile.java new file mode 100644 index 0000000..2c1f5ba --- /dev/null +++ b/src/main/java/cc/fascinated/bat/premium/PremiumProfile.java @@ -0,0 +1,134 @@ +package cc.fascinated.bat.premium; + +import cc.fascinated.bat.common.Serializable; +import com.google.gson.Gson; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.bson.Document; + +import java.util.Calendar; +import java.util.Date; + +/** + * @author Fascinated (fascinated7) + */ +@Getter +@Setter +@NoArgsConstructor +public class PremiumProfile extends Serializable { + /** + * The time the premium was activated + */ + private Date activatedAt; + + /** + * The time the premium expires + */ + private Date expiresAt; + + /** + * The type of premium + */ + private Type type; + + /** + * Checks if the guild has premium + * + * @return whether the guild has premium + */ + public boolean hasPremium() { + return this.type == Type.INFINITE || (this.expiresAt != null && this.expiresAt.after(new Date())); + } + + /** + * Adds a month to the premium time + */ + public void addTime(int months) { + if (this.type == null) { // If the type is null, set it to monthly + this.type = Type.MONTHLY; + } + if (this.expiresAt == null) { + this.expiresAt = new Date(); + } + Calendar calendar = Calendar.getInstance(); + calendar.setTime(new Date()); + calendar.add(Calendar.MONTH, months); + this.expiresAt = calendar.getTime(); + this.type = Type.MONTHLY; + } + + /** + * Adds a month to the premium time + */ + public void addTime() { + addTime(1); + } + + /** + * Adds infinite time to the premium + */ + public void addInfiniteTime() { + this.type = Type.INFINITE; + this.expiresAt = null; + this.activatedAt = new Date(); + } + + /** + * Removes the premium from the guild + */ + public void removePremium() { + this.activatedAt = null; + this.expiresAt = null; + this.type = null; + } + + /** + * Checks if the premium is infinite + * + * @return whether the premium is infinite + */ + public boolean isInfinite() { + return this.type == Type.INFINITE; + } + + /** + * Checks if the premium has expired + * + * @return whether the premium has expired + */ + public boolean hasExpired() { + return this.expiresAt != null && this.expiresAt.before(new Date()); + } + + /** + * The premium type for the guild + */ + public enum Type { + INFINITE, + MONTHLY + } + + @Override + public void load(Document document, Gson gson) { + this.activatedAt = (Date) document.getOrDefault("activatedAt", new Date()); + this.expiresAt = (Date) document.getOrDefault("expiresAt", null); + this.type = document.containsKey("type") ? Type.valueOf(document.getString("type")) : null; + } + + @Override + public Document serialize(Gson gson) { + Document document = new Document(); + document.put("activatedAt", this.activatedAt); + document.put("expiresAt", this.expiresAt); + document.put("type", this.type.name()); + return document; + } + + @Override + public void reset() { + this.activatedAt = null; + this.expiresAt = null; + this.type = null; + } +} diff --git a/src/main/java/cc/fascinated/bat/repository/GuildRepository.java b/src/main/java/cc/fascinated/bat/repository/GuildRepository.java deleted file mode 100644 index c072a1c..0000000 --- a/src/main/java/cc/fascinated/bat/repository/GuildRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package cc.fascinated.bat.repository; - -import cc.fascinated.bat.model.BatGuild; -import org.springframework.data.mongodb.repository.MongoRepository; - -/** - * @author Fascinated (fascinated7) - */ -public interface GuildRepository extends MongoRepository { -} \ No newline at end of file diff --git a/src/main/java/cc/fascinated/bat/repository/UserRepository.java b/src/main/java/cc/fascinated/bat/repository/UserRepository.java deleted file mode 100644 index 959ec3b..0000000 --- a/src/main/java/cc/fascinated/bat/repository/UserRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package cc.fascinated.bat.repository; - -import cc.fascinated.bat.model.BatUser; -import org.springframework.data.mongodb.repository.MongoRepository; - -/** - * @author Fascinated (fascinated7) - */ -public interface UserRepository extends MongoRepository { -} \ No newline at end of file diff --git a/src/main/java/cc/fascinated/bat/service/CommandService.java b/src/main/java/cc/fascinated/bat/service/CommandService.java index 1371da8..def6e05 100644 --- a/src/main/java/cc/fascinated/bat/service/CommandService.java +++ b/src/main/java/cc/fascinated/bat/service/CommandService.java @@ -27,7 +27,7 @@ import java.util.*; * @author Fascinated (fascinated7) */ @Service -@Log4j2 +@Log4j2(topic = "Command Service") @Getter @DependsOn("discordService") public class CommandService extends ListenerAdapter { diff --git a/src/main/java/cc/fascinated/bat/service/DiscordService.java b/src/main/java/cc/fascinated/bat/service/DiscordService.java index 3110ce6..3e31725 100644 --- a/src/main/java/cc/fascinated/bat/service/DiscordService.java +++ b/src/main/java/cc/fascinated/bat/service/DiscordService.java @@ -3,6 +3,7 @@ package cc.fascinated.bat.service; import cc.fascinated.bat.common.NumberFormatter; import cc.fascinated.bat.common.TimerUtils; import lombok.Getter; +import lombok.extern.log4j.Log4j2; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Activity; @@ -20,6 +21,7 @@ import java.util.List; */ @Service @Getter +@Log4j2(topic = "Discord Service") public class DiscordService { /** * The JDA instance @@ -37,6 +39,7 @@ public class DiscordService { public DiscordService( @Value("${discord.token}") String token ) throws Exception { + log.info("Starting Discord bot..."); JDA = JDABuilder.create(token, EnumSet.of( GatewayIntent.GUILD_MESSAGES, GatewayIntent.MESSAGE_CONTENT, @@ -51,6 +54,7 @@ public class DiscordService { CacheFlag.SCHEDULED_EVENTS ).build() .awaitReady(); + log.info("Connected to Discord as {}", JDA.getSelfUser().getEffectiveName()); TimerUtils.scheduleRepeating(this::updateActivity, 0, 1000 * 60 * 2); } diff --git a/src/main/java/cc/fascinated/bat/service/EventService.java b/src/main/java/cc/fascinated/bat/service/EventService.java index 9a456fa..13e3a50 100644 --- a/src/main/java/cc/fascinated/bat/service/EventService.java +++ b/src/main/java/cc/fascinated/bat/service/EventService.java @@ -27,7 +27,7 @@ import java.util.Set; * @author Fascinated (fascinated7) */ @Service -@Log4j2 +@Log4j2(topic = "Event Service") @DependsOn("discordService") public class EventService extends ListenerAdapter { /** diff --git a/src/main/java/cc/fascinated/bat/service/FeatureService.java b/src/main/java/cc/fascinated/bat/service/FeatureService.java index b690cbf..c48b324 100644 --- a/src/main/java/cc/fascinated/bat/service/FeatureService.java +++ b/src/main/java/cc/fascinated/bat/service/FeatureService.java @@ -21,7 +21,7 @@ import java.util.Map; */ @Service @Getter -@Log4j2 +@Log4j2(topic = "Feature Service") @DependsOn("commandService") public class FeatureService { public static FeatureService INSTANCE; diff --git a/src/main/java/cc/fascinated/bat/service/GuildService.java b/src/main/java/cc/fascinated/bat/service/GuildService.java index 9d34534..318e6d7 100644 --- a/src/main/java/cc/fascinated/bat/service/GuildService.java +++ b/src/main/java/cc/fascinated/bat/service/GuildService.java @@ -1,57 +1,63 @@ package cc.fascinated.bat.service; +import cc.fascinated.bat.common.TimerUtils; import cc.fascinated.bat.model.BatGuild; -import cc.fascinated.bat.repository.GuildRepository; +import cc.fascinated.bat.premium.PremiumProfile; +import com.mongodb.client.model.Filters; import lombok.Getter; import lombok.NonNull; import lombok.extern.log4j.Log4j2; -import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.events.guild.GuildJoinEvent; +import net.dv8tion.jda.api.events.guild.GuildLeaveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import net.jodah.expiringmap.ExpiringMap; +import org.bson.Document; +import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.DependsOn; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import java.util.*; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; /** * @author Fascinated (fascinated7) */ @Service -@Log4j2 +@Log4j2(topic = "Guild Service") @Getter -@DependsOn("discordService") +@DependsOn({"discordService", "mongoService"}) public class GuildService extends ListenerAdapter { + private static final long SAVE_INTERVAL = TimeUnit.MINUTES.toMillis(5); + /** * The cached guilds */ - private final Map guilds = ExpiringMap.builder() - .expiration(6, TimeUnit.HOURS) - .build(); - - /** - * The guild repository to use - */ - private final GuildRepository guildRepository; + private final Map guilds = new HashMap<>(); @Autowired - public GuildService(@NonNull GuildRepository guildRepository) { - this.guildRepository = guildRepository; + public GuildService() { + TimerUtils.scheduleRepeating(() -> { + long before = System.currentTimeMillis(); + for (BatGuild guild : guilds.values()) { + guild.save(); + } + log.info("Saved {} guilds in {}ms", guilds.size(), System.currentTimeMillis() - before); + }, SAVE_INTERVAL, SAVE_INTERVAL); + DiscordService.JDA.addEventListener(this); } @Scheduled(cron = "0 0 0 * * *") private void validatePremiumStatus() { for (BatGuild guild : guilds.values()) { - BatGuild.Premium premium = guild.getPremium(); - if (premium.getExpiresAt() != null && premium.getExpiresAt().before(new Date())) { - premium.removePremium(); - guildRepository.save(guild); - log.info("Removed premium status from guild \"{}\"", guild.getName()); + PremiumProfile premium = guild.getPremiumProfile(); + if (!premium.hasExpired()) { + return; } + premium.removePremium(); + log.info("Removed premium status from guild \"{}\"", guild.getName()); } } @@ -62,51 +68,37 @@ public class GuildService extends ListenerAdapter { * @return The guild */ public BatGuild getGuild(@NonNull String id) { + long before = System.currentTimeMillis(); + // Guild is cached if (guilds.containsKey(id)) { return guilds.get(id); } - if (DiscordService.JDA.getGuildById(id) == null) { - return null; - } - long start = System.currentTimeMillis(); - Optional optionalGuild = guildRepository.findById(id); - - if (optionalGuild.isPresent()) { - BatGuild guild = optionalGuild.get(); + // Guild is not cached + Document document = MongoService.INSTANCE.getGuildsCollection().find(Filters.eq("_id", id)).first(); + if (document != null) { + BatGuild guild = new BatGuild(id, document); guilds.put(id, guild); + log.info("Loaded guild \"{}\" in {}ms", guild.getName(),System.currentTimeMillis() - before); return guild; } - BatGuild guild = guildRepository.save(new BatGuild(id)); - log.info("Created guild \"{}\" in {}ms", guild.getName(), System.currentTimeMillis() - start); + // New guild + BatGuild guild = new BatGuild(id, new Document()); + guilds.put(id, guild); + log.info("Created guild \"{}\" - \"{}\"", guild.getName(), guild.getId()); return guild; } - /** - * Saves a guild - * - * @param guild The guild to save - */ - public void saveGuild(@NonNull BatGuild guild) { - guildRepository.save(guild); - } - - /** - * Gets all guilds - * - * @return all guilds - */ - public List getAllGuilds() { - List guilds = new ArrayList<>(); - for (Guild guild : DiscordService.JDA.getGuilds()) { - guilds.add(getGuild(guild.getId())); - } - return guilds; - } - @Override public final void onGuildJoin(GuildJoinEvent event) { - Guild guild = event.getGuild(); + BatGuild guild = getGuild(event.getGuild().getId()); log.info("Joined guild \"{}\"", guild.getName()); - getGuild(guild.getId()); // Ensure the guild is in the database + } + + @Override + public void onGuildLeave(@NotNull GuildLeaveEvent event) { + BatGuild guild = getGuild(event.getGuild().getId()); + log.info("Left guild \"{}\"", guild.getName()); + guild.save(); + guilds.remove(guild.getId()); } } diff --git a/src/main/java/cc/fascinated/bat/service/MongoService.java b/src/main/java/cc/fascinated/bat/service/MongoService.java new file mode 100644 index 0000000..93260bb --- /dev/null +++ b/src/main/java/cc/fascinated/bat/service/MongoService.java @@ -0,0 +1,40 @@ +package cc.fascinated.bat.service; + +import com.mongodb.client.MongoCollection; +import org.bson.Document; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.stereotype.Service; + +/** + * @author Fascinated (fascinated7) + */ +@Service +public class MongoService { + public static MongoService INSTANCE; + private final MongoTemplate mongo; + + @Autowired + public MongoService(MongoTemplate mongo) { + INSTANCE = this; + this.mongo = mongo; + } + + /** + * Get the guilds collection + * + * @return The guilds collection + */ + public MongoCollection getGuildsCollection() { + return mongo.getCollection("guilds"); + } + + /** + * Get the users collection + * + * @return The users collection + */ + public MongoCollection getUsersCollection() { + return mongo.getCollection("users"); + } +} diff --git a/src/main/java/cc/fascinated/bat/service/SpotifyService.java b/src/main/java/cc/fascinated/bat/service/SpotifyService.java index 991dde1..4feb680 100644 --- a/src/main/java/cc/fascinated/bat/service/SpotifyService.java +++ b/src/main/java/cc/fascinated/bat/service/SpotifyService.java @@ -26,7 +26,7 @@ import java.util.concurrent.TimeUnit; */ @Service @Getter -@Log4j2 +@Log4j2(topic = "Spotify Service") public class SpotifyService { /** * The access token map. @@ -189,7 +189,6 @@ public class SpotifyService { AuthorizationCodeCredentials credentials = api.authorizationCodeRefresh().build().execute(); profile.setAccessToken(credentials.getAccessToken()); profile.setExpiresAt(System.currentTimeMillis() + (credentials.getExpiresIn() * 1000)); - userService.saveUser(user); log.info("Refreshed Spotify token for user {}", user.getName()); } catch (SpotifyWebApiException ex) { log.error("Failed to refresh Spotify token", ex); @@ -213,7 +212,6 @@ public class SpotifyService { profile.setAccessToken(credentials.getAccessToken()); profile.setRefreshToken(credentials.getRefreshToken()); profile.setExpiresAt(System.currentTimeMillis() + (credentials.getExpiresIn() * 1000)); - userService.saveUser(user); log.info("Linked Spotify account for user {}", user.getName()); } diff --git a/src/main/java/cc/fascinated/bat/service/UserService.java b/src/main/java/cc/fascinated/bat/service/UserService.java index 1a66c7d..aaa52c1 100644 --- a/src/main/java/cc/fascinated/bat/service/UserService.java +++ b/src/main/java/cc/fascinated/bat/service/UserService.java @@ -1,73 +1,70 @@ package cc.fascinated.bat.service; +import cc.fascinated.bat.common.TimerUtils; import cc.fascinated.bat.model.BatUser; -import cc.fascinated.bat.repository.UserRepository; +import com.mongodb.client.model.Filters; import lombok.Getter; import lombok.NonNull; import lombok.extern.log4j.Log4j2; -import net.jodah.expiringmap.ExpiringMap; +import org.bson.Document; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Service; +import java.util.HashMap; import java.util.Map; -import java.util.Optional; import java.util.concurrent.TimeUnit; /** * @author Fascinated (fascinated7) */ @Service -@Log4j2 +@Log4j2(topic = "User Service") @Getter -@DependsOn("discordService") +@DependsOn({"discordService", "mongoService"}) public class UserService { + private static final long SAVE_INTERVAL = TimeUnit.MINUTES.toMillis(5); + /** * The cached users */ - private final Map users = ExpiringMap.builder() - .expiration(6, TimeUnit.HOURS) - .build(); - - /** - * The user repository to use - */ - private final UserRepository userRepository; + private final Map users = new HashMap<>(); @Autowired - public UserService(@NonNull UserRepository userRepository) { - this.userRepository = userRepository; + public UserService() { + TimerUtils.scheduleRepeating(() -> { + long before = System.currentTimeMillis(); + for (BatUser user : users.values()) { + user.save(); + } + log.info("Saved {} users in {}ms", users.size(), System.currentTimeMillis() - before); + }, SAVE_INTERVAL, SAVE_INTERVAL); } /** - * Gets a user by their ID + * Gets a user by its ID * * @param id The ID of the user * @return The user */ public BatUser getUser(@NonNull String id) { + long before = System.currentTimeMillis(); + // User is cached if (users.containsKey(id)) { return users.get(id); } - - long start = System.currentTimeMillis(); - Optional optionalUser = userRepository.findById(id); - if (optionalUser.isPresent()) { - BatUser user = optionalUser.get(); + // 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 user = userRepository.save(new BatUser(id)); - log.info("Created user for \"{}\" in {}ms", user.getDiscordUser().getName(), System.currentTimeMillis() - start); + // New user + BatUser user = new BatUser(id, new Document()); + users.put(id, user); + log.info("Created user \"{}\" - \"{}\"", user.getName(), user.getId()); return user; } - - /** - * Saves a user - * - * @param user The user to save - */ - public void saveUser(@NonNull BatUser user) { - userRepository.save(user); - } }