diff --git a/src/main/java/cc/fascinated/bat/command/BatCommandExecutor.java b/src/main/java/cc/fascinated/bat/command/BatCommandExecutor.java index 8aa1b23..277b597 100644 --- a/src/main/java/cc/fascinated/bat/command/BatCommandExecutor.java +++ b/src/main/java/cc/fascinated/bat/command/BatCommandExecutor.java @@ -1,7 +1,7 @@ package cc.fascinated.bat.command; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.user.BatUser; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; diff --git a/src/main/java/cc/fascinated/bat/common/Profile.java b/src/main/java/cc/fascinated/bat/common/Profile.java index eb312ce..83adbfc 100644 --- a/src/main/java/cc/fascinated/bat/common/Profile.java +++ b/src/main/java/cc/fascinated/bat/common/Profile.java @@ -2,15 +2,22 @@ package cc.fascinated.bat.common; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.Setter; import org.springframework.data.annotation.Transient; /** * @author Fascinated (fascinated7) */ -@AllArgsConstructor @Getter +@Getter @Setter public class Profile { /** * The key of the profile. */ - @Transient private final String profileKey; + private String profileKey; + + public Profile(String profileKey) { + this.profileKey = profileKey; + } + + public Profile() {} } diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java b/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java new file mode 100644 index 0000000..f0971b2 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/NumberOneScoreFeedListener.java @@ -0,0 +1,102 @@ +package cc.fascinated.bat.features.scoresaber; + +import cc.fascinated.bat.common.Colors; +import cc.fascinated.bat.common.DateUtils; +import cc.fascinated.bat.common.NumberUtils; +import cc.fascinated.bat.common.ScoreSaberUtils; +import cc.fascinated.bat.event.EventListener; +import cc.fascinated.bat.features.scoresaber.profiles.GuildNumberOneScoreFeedProfile; +import cc.fascinated.bat.features.scoresaber.profiles.GuildUserScoreFeedProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberLeaderboardToken; +import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberPlayerScoreToken; +import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberScoreToken; +import cc.fascinated.bat.service.DiscordService; +import cc.fascinated.bat.service.GuildService; +import lombok.extern.log4j.Log4j2; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component @Log4j2 +public class NumberOneScoreFeedListener implements EventListener { + private final GuildService guildService; + + @Autowired + public NumberOneScoreFeedListener(GuildService guildService) { + this.guildService = guildService; + } + + @Override + public void onScoresaberScoreReceived(ScoreSaberPlayerScoreToken score, ScoreSaberLeaderboardToken leaderboard, + ScoreSaberScoreToken.LeaderboardPlayerInfo player) { + if (score.getScore().getRank() != 1) { // Only send if the score is a #1 score + return; + } + if (!leaderboard.isRanked()) { // Only send if the leaderboard is ranked + return; + } + + for (Guild guild : DiscordService.JDA.getGuilds()) { + BatGuild batGuild = guildService.getGuild(guild.getId()); + if (batGuild == null) { + continue; + } + GuildNumberOneScoreFeedProfile profile = batGuild.getProfile(GuildNumberOneScoreFeedProfile.class); + if (profile == null || profile.getChannelId() == null) { + continue; + } + + TextChannel channel = profile.getAsTextChannel(); + 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(this.buildScoreEmbed(score)).queue(); + } + } + + /** + * Builds an embed for a score. + * + * @param score The score. + * @return The embed. + */ + public MessageEmbed buildScoreEmbed(ScoreSaberPlayerScoreToken score) { + ScoreSaberScoreToken scoreToken = score.getScore(); + ScoreSaberLeaderboardToken leaderboardToken = score.getLeaderboard(); + ScoreSaberScoreToken.LeaderboardPlayerInfo playerInfo = scoreToken.getLeaderboardPlayerInfo(); + return new EmbedBuilder() + .setAuthor(playerInfo.getName() + " just set a new #1!", "https://scoresaber.com/u/%s".formatted(playerInfo.getId()), + "https://cdn.scoresaber.com/avatars/%s.jpg".formatted(playerInfo.getId())) + .setDescription("**%s** (%s%s)\n[[Map Link]](%s) [[SS Profile]](%s)".formatted( + leaderboardToken.getSongName(), + ScoreSaberUtils.getFormattedDifficulty(leaderboardToken.getDifficulty().getDifficulty()), + leaderboardToken.isRanked() ? " " + leaderboardToken.getStars() + "⭐" : "", + "https://scoresaber.com/leaderboard/%s".formatted(leaderboardToken.getId()), + "https://scoresaber.com/u/%s".formatted(playerInfo.getId()) + )) + .addField("Accuracy", "%s%%".formatted( + leaderboardToken.getMaxScore() == 0 ? "N/A" : NumberUtils.formatNumberCommas(((double) scoreToken.getBaseScore() / leaderboardToken.getMaxScore()) * 100) + ), true) + .addField("Raw PP", scoreToken.getPp() == 0 ? "Unranked" : NumberUtils.formatNumberCommas(scoreToken.getPp()), true) + .addField("Rank", "#%s".formatted(NumberUtils.formatNumberCommas(scoreToken.getRank())), true) + .addField("Misses", "%s".formatted(scoreToken.getMissedNotes()), true) + .addField("Bad Cuts", "%s".formatted(scoreToken.getBadCuts()), true) + .addField("Max Combo", "%s %s".formatted( + scoreToken.getMaxCombo(), + scoreToken.getMaxCombo() == leaderboardToken.getMaxScore() ? "(FC)" : "" + ), true) + .setColor(Colors.DEFAULT) + .setTimestamp(DateUtils.getDateFromString(scoreToken.getTimeSet()).toInstant()) + .build(); + } +} 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 e659f83..7631243 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/UserScoreFeedListener.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/UserScoreFeedListener.java @@ -5,11 +5,11 @@ import cc.fascinated.bat.common.DateUtils; import cc.fascinated.bat.common.NumberUtils; import cc.fascinated.bat.common.ScoreSaberUtils; import cc.fascinated.bat.event.EventListener; +import cc.fascinated.bat.features.scoresaber.profiles.GuildUserScoreFeedProfile; import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberLeaderboardToken; import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberPlayerScoreToken; import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberScoreToken; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.guild.profiles.ScoreSaberUserScoreFeedProfile; +import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.service.DiscordService; import cc.fascinated.bat.service.GuildService; import lombok.extern.log4j.Log4j2; @@ -40,7 +40,7 @@ public class UserScoreFeedListener implements EventListener { if (batGuild == null) { continue; } - ScoreSaberUserScoreFeedProfile profile = batGuild.getProfile(ScoreSaberUserScoreFeedProfile.class); + GuildUserScoreFeedProfile profile = batGuild.getProfile(GuildUserScoreFeedProfile.class); if (profile == null || profile.getChannelId() == null || !profile.getTrackedUsers().contains(player.getId())) { continue; } 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 new file mode 100644 index 0000000..adf3042 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ChannelSubCommand.java @@ -0,0 +1,59 @@ +package cc.fascinated.bat.features.scoresaber.command.numberone; + +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.common.TextChannelUtils; +import cc.fascinated.bat.features.scoresaber.profiles.GuildNumberOneScoreFeedProfile; +import cc.fascinated.bat.features.scoresaber.profiles.GuildUserScoreFeedProfile; +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; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("scoresaber-number-one-feed:channel.sub") +public class ChannelSubCommand extends BatSubCommand { + private final GuildService guildService; + + @Autowired + public ChannelSubCommand(GuildService guildService) { + this.guildService = guildService; + } + + @Override + public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) { + GuildNumberOneScoreFeedProfile profile = guild.getProfile(GuildNumberOneScoreFeedProfile.class); + OptionMapping option = interaction.getOption("channel"); + if (option == null) { + if (!TextChannelUtils.isValidChannel(profile.getChannelId())) { + interaction.replyEmbeds(EmbedUtils.buildErrorEmbed("Please provide a channel to set the ScoreSaber #1 feed channel to").build()).queue(); + return; + } + interaction.replyEmbeds(EmbedUtils.buildSuccessEmbed("The current ScoreSaber #1 feed channel is %s" + .formatted(TextChannelUtils.getChannelMention(profile.getChannelId()))).build()).queue(); + return; + } + + GuildChannelUnion targetChannel = option.getAsChannel(); + if (targetChannel.getType() != ChannelType.TEXT) { + interaction.replyEmbeds(EmbedUtils.buildErrorEmbed("Invalid channel type, please provide a text channel").build()).queue(); + return; + } + + profile.setChannelId(targetChannel.getId()); + guildService.saveGuild(guild); + + interaction.replyEmbeds(EmbedUtils.buildSuccessEmbed("Successfully set the ScoreSaber #1 feed channel to %s" + .formatted(targetChannel.asTextChannel().getAsMention())).build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ClearChannelSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ClearChannelSubCommand.java new file mode 100644 index 0000000..6592798 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/ClearChannelSubCommand.java @@ -0,0 +1,40 @@ +package cc.fascinated.bat.features.scoresaber.command.numberone; + +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.common.TextChannelUtils; +import cc.fascinated.bat.features.scoresaber.profiles.GuildNumberOneScoreFeedProfile; +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; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("scoresaber-number-one-feed:clear-channel.sub") +public class ClearChannelSubCommand extends BatSubCommand { + private final GuildService guildService; + + @Autowired + public ClearChannelSubCommand(GuildService guildService) { + this.guildService = guildService; + } + + @Override + public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) { + GuildNumberOneScoreFeedProfile profile = guild.getProfile(GuildNumberOneScoreFeedProfile.class); + profile.setChannelId(null); + guildService.saveGuild(guild); + + interaction.replyEmbeds(EmbedUtils.buildSuccessEmbed("Successfully cleared the ScoreSaber #1 feed channel").build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/NunberOneFeedCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/NunberOneFeedCommand.java new file mode 100644 index 0000000..89fa82f --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/numberone/NunberOneFeedCommand.java @@ -0,0 +1,35 @@ +package cc.fascinated.bat.features.scoresaber.command.numberone; + +import cc.fascinated.bat.command.BatCommand; +import lombok.NonNull; +import net.dv8tion.jda.api.Permission; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; +import net.dv8tion.jda.internal.interactions.CommandDataImpl; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("scoresaber-number-one-feed") +public class NunberOneFeedCommand extends BatCommand { + public NunberOneFeedCommand(@NonNull ApplicationContext context) { + super("scoresaber-number-one-feed"); + super.setCategory(Category.BEAT_SABER); + + super.addSubCommand("channel", context.getBean(ChannelSubCommand.class)); + super.addSubCommand("clear-channel", context.getBean(ClearChannelSubCommand.class)); + + super.setDescription("ScoreSaber #1 score feed commands"); + super.setCommandData(new CommandDataImpl(this.getName(), this.getDescription()) + .addSubcommands(new SubcommandData("channel", "Edit the channel the score feed is sent in") + .addOptions(new OptionData(OptionType.CHANNEL, "channel", "Set the channel to send the score feed in", false)) + ).setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER)) + .addSubcommands(new SubcommandData("clear-channel", "Disable the score feed")) + .setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER)) + ); + } +} 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 37d191f..c69e52c 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 @@ -3,9 +3,9 @@ package cc.fascinated.bat.features.scoresaber.command.scoresaber; import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberAccountToken; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.user.BatUser; -import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.features.scoresaber.profiles.UserScoreSaberProfile; import cc.fascinated.bat.service.ScoreSaberService; import cc.fascinated.bat.service.UserService; import lombok.NonNull; @@ -55,7 +55,7 @@ public class LinkSubCommand extends BatSubCommand { return; } - ((ScoreSaberProfile) user.getProfile(ScoreSaberProfile.class)).setId(id); + ((UserScoreSaberProfile) user.getProfile(UserScoreSaberProfile.class)).setId(id); userService.saveUser(user); interaction.replyEmbeds(EmbedUtils.buildSuccessEmbed("Successfully linked your [ScoreSaber](%s) profile".formatted( "https://scoresaber.com/u/%s".formatted(id) diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/MeSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/MeSubCommand.java index 4536b86..ccf7cf2 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/MeSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/MeSubCommand.java @@ -1,8 +1,8 @@ package cc.fascinated.bat.features.scoresaber.command.scoresaber; import cc.fascinated.bat.command.BatSubCommand; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.user.BatUser; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.ScoreSaberService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java index e0f1bab..7d9de96 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/ScoreSaberCommand.java @@ -6,9 +6,9 @@ import cc.fascinated.bat.common.DateUtils; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.NumberUtils; import cc.fascinated.bat.model.beatsaber.scoresaber.ScoreSaberAccountToken; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.user.BatUser; -import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.features.scoresaber.profiles.UserScoreSaberProfile; import cc.fascinated.bat.service.ScoreSaberService; import lombok.NonNull; import net.dv8tion.jda.api.EmbedBuilder; @@ -67,7 +67,7 @@ public class ScoreSaberCommand extends BatCommand { * @param interaction The interaction */ public static void sendProfileEmbed(boolean isSelf, BatUser user, ScoreSaberService scoreSaberService, SlashCommandInteraction interaction) { - ScoreSaberProfile profile = user.getProfile(ScoreSaberProfile.class); + UserScoreSaberProfile profile = user.getProfile(UserScoreSaberProfile.class); if (profile.getId() == null) { if (!isSelf) { interaction.replyEmbeds(EmbedUtils.buildErrorEmbed("%s does not have a linked ScoreSaber account" diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/UserSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/UserSubCommand.java index 2ed99af..a6ba180 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/UserSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/scoresaber/UserSubCommand.java @@ -2,8 +2,8 @@ package cc.fascinated.bat.features.scoresaber.command.scoresaber; import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.common.EmbedUtils; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.user.BatUser; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.ScoreSaberService; import cc.fascinated.bat.service.UserService; import lombok.NonNull; 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 a9db633..4ea6a36 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 @@ -3,9 +3,9 @@ package cc.fascinated.bat.features.scoresaber.command.userfeed; import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.common.EmbedUtils; import cc.fascinated.bat.common.TextChannelUtils; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.guild.profiles.ScoreSaberUserScoreFeedProfile; -import cc.fascinated.bat.model.user.BatUser; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.features.scoresaber.profiles.GuildUserScoreFeedProfile; +import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.GuildService; import lombok.NonNull; import net.dv8tion.jda.api.entities.Member; @@ -31,7 +31,7 @@ public class ChannelSubCommand extends BatSubCommand { @Override public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) { - ScoreSaberUserScoreFeedProfile profile = guild.getProfile(ScoreSaberUserScoreFeedProfile.class); + GuildUserScoreFeedProfile profile = guild.getProfile(GuildUserScoreFeedProfile.class); OptionMapping option = interaction.getOption("channel"); if (option == null) { if (!TextChannelUtils.isValidChannel(profile.getChannelId())) { diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ClearChannelSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ClearChannelSubCommand.java new file mode 100644 index 0000000..46f3729 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ClearChannelSubCommand.java @@ -0,0 +1,37 @@ +package cc.fascinated.bat.features.scoresaber.command.userfeed; + +import cc.fascinated.bat.command.BatSubCommand; +import cc.fascinated.bat.common.EmbedUtils; +import cc.fascinated.bat.features.scoresaber.profiles.GuildNumberOneScoreFeedProfile; +import cc.fascinated.bat.features.scoresaber.profiles.GuildUserScoreFeedProfile; +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.concrete.TextChannel; +import net.dv8tion.jda.api.interactions.commands.SlashCommandInteraction; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @author Fascinated (fascinated7) + */ +@Component("scoresaber-userfeed:clear-channel.sub") +public class ClearChannelSubCommand extends BatSubCommand { + private final GuildService guildService; + + @Autowired + public ClearChannelSubCommand(GuildService guildService) { + this.guildService = guildService; + } + + @Override + public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) { + GuildUserScoreFeedProfile profile = guild.getProfile(GuildUserScoreFeedProfile.class); + profile.setChannelId(null); + guildService.saveGuild(guild); + + interaction.replyEmbeds(EmbedUtils.buildSuccessEmbed("Successfully cleared the ScoreSaber feed channel").build()).queue(); + } +} diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ClearUsersSubCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ClearUsersSubCommand.java index e35a1cb..33c4b7a 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ClearUsersSubCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/ClearUsersSubCommand.java @@ -2,9 +2,9 @@ package cc.fascinated.bat.features.scoresaber.command.userfeed; import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.common.EmbedUtils; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.guild.profiles.ScoreSaberUserScoreFeedProfile; -import cc.fascinated.bat.model.user.BatUser; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.features.scoresaber.profiles.GuildUserScoreFeedProfile; +import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.service.GuildService; import cc.fascinated.bat.service.UserService; import lombok.NonNull; @@ -28,7 +28,7 @@ public class ClearUsersSubCommand extends BatSubCommand { @Override public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) { - ScoreSaberUserScoreFeedProfile profile = guild.getProfile(ScoreSaberUserScoreFeedProfile.class); + GuildUserScoreFeedProfile profile = guild.getProfile(GuildUserScoreFeedProfile.class); profile.getTrackedUsers().clear(); guildService.saveGuild(guild); diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/UserFeedCommand.java b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/UserFeedCommand.java index a99a188..b8d389c 100644 --- a/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/UserFeedCommand.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/command/userfeed/UserFeedCommand.java @@ -17,25 +17,29 @@ import org.springframework.stereotype.Component; @Component("scoresaber-userfeed:feed.sub") public class UserFeedCommand extends BatCommand { public UserFeedCommand(@NonNull ApplicationContext context) { - super("scoresaber-userfeed"); + super("scoresaber-user-feed"); super.setCategory(Category.BEAT_SABER); super.addSubCommand("user", context.getBean(UserSubCommand.class)); super.addSubCommand("channel", context.getBean(ChannelSubCommand.class)); + super.addSubCommand("clear-channel", context.getBean(ClearChannelSubCommand.class)); super.addSubCommand("clear-users", context.getBean(ClearUsersSubCommand.class)); super.setDescription("ScoreSaber user score feed commands"); super.setCommandData(new CommandDataImpl(this.getName(), this.getDescription()) - .addSubcommands(new SubcommandData("user", "Edit your ScoreSaber score feed settings") + .addSubcommands(new SubcommandData("user", "Edit the users in the score feed") .addOptions(new OptionData(OptionType.USER, "user", "Add or remove a user from the score feed", false)) ).setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER)) .addSubcommands(new SubcommandData("clear-users", "Remove all users from the score feed")) .setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER)) - .addSubcommands(new SubcommandData("channel", "Edit your ScoreSaber score feed settings") + .addSubcommands(new SubcommandData("channel", "Edit the channel the score feed is sent in") .addOptions(new OptionData(OptionType.CHANNEL, "channel", "Set the channel to send the score feed in", false)) ).setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER)) + + .addSubcommands(new SubcommandData("clear-channel", "Disable the score feed")) + .setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.MANAGE_SERVER)) ); } } 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 16144ef..6fe1788 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 @@ -2,10 +2,10 @@ package cc.fascinated.bat.features.scoresaber.command.userfeed; import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.common.EmbedUtils; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.guild.profiles.ScoreSaberUserScoreFeedProfile; -import cc.fascinated.bat.model.user.BatUser; -import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.features.scoresaber.profiles.GuildUserScoreFeedProfile; +import cc.fascinated.bat.model.BatUser; +import cc.fascinated.bat.features.scoresaber.profiles.UserScoreSaberProfile; import cc.fascinated.bat.service.GuildService; import cc.fascinated.bat.service.UserService; import lombok.NonNull; @@ -33,7 +33,7 @@ public class UserSubCommand extends BatSubCommand { @Override public void execute(@NonNull BatGuild guild, @NonNull BatUser user, @NonNull TextChannel channel, @NonNull Member member, @NonNull SlashCommandInteraction interaction) { - ScoreSaberUserScoreFeedProfile profile = guild.getProfile(ScoreSaberUserScoreFeedProfile.class); + GuildUserScoreFeedProfile profile = guild.getProfile(GuildUserScoreFeedProfile.class); OptionMapping option = interaction.getOption("user"); if (option == null){ if (profile.getTrackedUsers().isEmpty()) { @@ -53,7 +53,7 @@ public class UserSubCommand extends BatSubCommand { User target = option.getAsUser(); BatUser targetUser = userService.getUser(target.getId()); - ScoreSaberProfile targetProfile = targetUser.getProfile(ScoreSaberProfile.class); + UserScoreSaberProfile targetProfile = targetUser.getProfile(UserScoreSaberProfile.class); if (targetProfile.getId() == null) { interaction.replyEmbeds(EmbedUtils.buildErrorEmbed("The user you are trying to track does not have a linked ScoreSaber profile").build()).queue(); return; diff --git a/src/main/java/cc/fascinated/bat/features/scoresaber/profiles/GuildNumberOneScoreFeedProfile.java b/src/main/java/cc/fascinated/bat/features/scoresaber/profiles/GuildNumberOneScoreFeedProfile.java new file mode 100644 index 0000000..d49a646 --- /dev/null +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/profiles/GuildNumberOneScoreFeedProfile.java @@ -0,0 +1,34 @@ +package cc.fascinated.bat.features.scoresaber.profiles; + +import cc.fascinated.bat.common.Profile; +import cc.fascinated.bat.service.DiscordService; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Fascinated (fascinated7) + */ +@Getter @Setter +public class GuildNumberOneScoreFeedProfile extends Profile { + public GuildNumberOneScoreFeedProfile() { + super("scoresaber-number-one-score-feed"); + } + + /** + * The channel ID of the score feed + */ + private String channelId; + + /** + * Gets the channel as a TextChannel + * + * @return the channel as a TextChannel + */ + public TextChannel getAsTextChannel() { + return DiscordService.JDA.getTextChannelById(channelId); + } +} diff --git a/src/main/java/cc/fascinated/bat/model/guild/profiles/ScoreSaberUserScoreFeedProfile.java b/src/main/java/cc/fascinated/bat/features/scoresaber/profiles/GuildUserScoreFeedProfile.java similarity index 91% rename from src/main/java/cc/fascinated/bat/model/guild/profiles/ScoreSaberUserScoreFeedProfile.java rename to src/main/java/cc/fascinated/bat/features/scoresaber/profiles/GuildUserScoreFeedProfile.java index 1b38861..aaeccc4 100644 --- a/src/main/java/cc/fascinated/bat/model/guild/profiles/ScoreSaberUserScoreFeedProfile.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/profiles/GuildUserScoreFeedProfile.java @@ -1,4 +1,4 @@ -package cc.fascinated.bat.model.guild.profiles; +package cc.fascinated.bat.features.scoresaber.profiles; import cc.fascinated.bat.common.Profile; import cc.fascinated.bat.service.DiscordService; @@ -13,8 +13,8 @@ import java.util.List; * @author Fascinated (fascinated7) */ @Getter @Setter -public class ScoreSaberUserScoreFeedProfile extends Profile { - public ScoreSaberUserScoreFeedProfile() { +public class GuildUserScoreFeedProfile extends Profile { + public GuildUserScoreFeedProfile() { super("scoresaber-user-score-feed"); } diff --git a/src/main/java/cc/fascinated/bat/model/user/profiles/ScoreSaberProfile.java b/src/main/java/cc/fascinated/bat/features/scoresaber/profiles/UserScoreSaberProfile.java similarity index 65% rename from src/main/java/cc/fascinated/bat/model/user/profiles/ScoreSaberProfile.java rename to src/main/java/cc/fascinated/bat/features/scoresaber/profiles/UserScoreSaberProfile.java index bbc1305..eca6493 100644 --- a/src/main/java/cc/fascinated/bat/model/user/profiles/ScoreSaberProfile.java +++ b/src/main/java/cc/fascinated/bat/features/scoresaber/profiles/UserScoreSaberProfile.java @@ -1,4 +1,4 @@ -package cc.fascinated.bat.model.user.profiles; +package cc.fascinated.bat.features.scoresaber.profiles; import cc.fascinated.bat.common.Profile; import lombok.Getter; @@ -8,13 +8,13 @@ import lombok.Setter; * @author Fascinated (fascinated7) */ @Setter @Getter -public class ScoreSaberProfile extends Profile { +public class UserScoreSaberProfile extends Profile { /** * The Account ID of the ScoreSaber profile */ private String id; - public ScoreSaberProfile() { + public UserScoreSaberProfile() { super("scoresaber"); } } diff --git a/src/main/java/cc/fascinated/bat/model/guild/BatGuild.java b/src/main/java/cc/fascinated/bat/model/BatGuild.java similarity index 97% rename from src/main/java/cc/fascinated/bat/model/guild/BatGuild.java rename to src/main/java/cc/fascinated/bat/model/BatGuild.java index 6301458..37eadce 100644 --- a/src/main/java/cc/fascinated/bat/model/guild/BatGuild.java +++ b/src/main/java/cc/fascinated/bat/model/BatGuild.java @@ -1,4 +1,4 @@ -package cc.fascinated.bat.model.guild; +package cc.fascinated.bat.model; import cc.fascinated.bat.common.Profile; import cc.fascinated.bat.service.DiscordService; diff --git a/src/main/java/cc/fascinated/bat/model/user/BatUser.java b/src/main/java/cc/fascinated/bat/model/BatUser.java similarity index 97% rename from src/main/java/cc/fascinated/bat/model/user/BatUser.java rename to src/main/java/cc/fascinated/bat/model/BatUser.java index 87002fa..f9d1029 100644 --- a/src/main/java/cc/fascinated/bat/model/user/BatUser.java +++ b/src/main/java/cc/fascinated/bat/model/BatUser.java @@ -1,4 +1,4 @@ -package cc.fascinated.bat.model.user; +package cc.fascinated.bat.model; import cc.fascinated.bat.common.Profile; import cc.fascinated.bat.service.DiscordService; diff --git a/src/main/java/cc/fascinated/bat/repository/GuildRepository.java b/src/main/java/cc/fascinated/bat/repository/GuildRepository.java index 34e6101..415891d 100644 --- a/src/main/java/cc/fascinated/bat/repository/GuildRepository.java +++ b/src/main/java/cc/fascinated/bat/repository/GuildRepository.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.repository; -import cc.fascinated.bat.model.guild.BatGuild; +import cc.fascinated.bat.model.BatGuild; import org.springframework.data.mongodb.repository.MongoRepository; /** diff --git a/src/main/java/cc/fascinated/bat/repository/UserRepository.java b/src/main/java/cc/fascinated/bat/repository/UserRepository.java index 3f8a69c..4637764 100644 --- a/src/main/java/cc/fascinated/bat/repository/UserRepository.java +++ b/src/main/java/cc/fascinated/bat/repository/UserRepository.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.repository; -import cc.fascinated.bat.model.user.BatUser; +import cc.fascinated.bat.model.BatUser; import org.springframework.data.mongodb.repository.MongoRepository; /** diff --git a/src/main/java/cc/fascinated/bat/service/CommandService.java b/src/main/java/cc/fascinated/bat/service/CommandService.java index edd6611..2802b00 100644 --- a/src/main/java/cc/fascinated/bat/service/CommandService.java +++ b/src/main/java/cc/fascinated/bat/service/CommandService.java @@ -3,15 +3,11 @@ package cc.fascinated.bat.service; import cc.fascinated.bat.command.BatCommand; import cc.fascinated.bat.command.BatSubCommand; import cc.fascinated.bat.common.EmbedUtils; -import cc.fascinated.bat.features.scoresaber.command.scoresaber.LinkSubCommand; -import cc.fascinated.bat.features.scoresaber.command.scoresaber.MeSubCommand; +import cc.fascinated.bat.features.scoresaber.command.numberone.NunberOneFeedCommand; import cc.fascinated.bat.features.scoresaber.command.scoresaber.ScoreSaberCommand; -import cc.fascinated.bat.features.scoresaber.command.userfeed.ChannelSubCommand; -import cc.fascinated.bat.features.scoresaber.command.userfeed.ClearUsersSubCommand; import cc.fascinated.bat.features.scoresaber.command.userfeed.UserFeedCommand; -import cc.fascinated.bat.features.scoresaber.command.userfeed.UserSubCommand; -import cc.fascinated.bat.model.guild.BatGuild; -import cc.fascinated.bat.model.user.BatUser; +import cc.fascinated.bat.model.BatGuild; +import cc.fascinated.bat.model.BatUser; import lombok.NonNull; import lombok.extern.log4j.Log4j2; import net.dv8tion.jda.api.JDA; @@ -56,6 +52,7 @@ public class CommandService extends ListenerAdapter { // Guild commands registerCommand(context.getBean(UserFeedCommand.class)); + registerCommand(context.getBean(NunberOneFeedCommand.class)); // Global commands registerCommand(context.getBean(ScoreSaberCommand.class)); diff --git a/src/main/java/cc/fascinated/bat/service/DiscordService.java b/src/main/java/cc/fascinated/bat/service/DiscordService.java index fca202a..4d728f7 100644 --- a/src/main/java/cc/fascinated/bat/service/DiscordService.java +++ b/src/main/java/cc/fascinated/bat/service/DiscordService.java @@ -36,7 +36,6 @@ public class DiscordService { TimerUtils.scheduleRepeating(this::updateActivity, 0, 1000 * 60 * 5); } - /** * Updates the activity of the bot */ diff --git a/src/main/java/cc/fascinated/bat/service/EventService.java b/src/main/java/cc/fascinated/bat/service/EventService.java index 2985fd7..8e3eb3a 100644 --- a/src/main/java/cc/fascinated/bat/service/EventService.java +++ b/src/main/java/cc/fascinated/bat/service/EventService.java @@ -1,6 +1,7 @@ package cc.fascinated.bat.service; import cc.fascinated.bat.event.EventListener; +import cc.fascinated.bat.features.scoresaber.NumberOneScoreFeedListener; import cc.fascinated.bat.features.scoresaber.UserScoreFeedListener; import lombok.NonNull; import lombok.extern.log4j.Log4j2; @@ -24,7 +25,8 @@ public class EventService { @Autowired public EventService(@NonNull ApplicationContext context) { registerListeners( - context.getBean(UserScoreFeedListener.class) + context.getBean(UserScoreFeedListener.class), + context.getBean(NumberOneScoreFeedListener.class) ); log.info("Registered {} listeners.", LISTENERS.size()); } diff --git a/src/main/java/cc/fascinated/bat/service/GuildService.java b/src/main/java/cc/fascinated/bat/service/GuildService.java index 350dcac..9f2b400 100644 --- a/src/main/java/cc/fascinated/bat/service/GuildService.java +++ b/src/main/java/cc/fascinated/bat/service/GuildService.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.service; -import cc.fascinated.bat.model.guild.BatGuild; +import cc.fascinated.bat.model.BatGuild; import cc.fascinated.bat.repository.GuildRepository; import lombok.NonNull; import lombok.extern.log4j.Log4j2; diff --git a/src/main/java/cc/fascinated/bat/service/ScoreSaberService.java b/src/main/java/cc/fascinated/bat/service/ScoreSaberService.java index 6aa2fdd..c5410c1 100644 --- a/src/main/java/cc/fascinated/bat/service/ScoreSaberService.java +++ b/src/main/java/cc/fascinated/bat/service/ScoreSaberService.java @@ -7,7 +7,7 @@ import cc.fascinated.bat.event.EventListener; import cc.fascinated.bat.exception.BadRequestException; import cc.fascinated.bat.exception.ResourceNotFoundException; import cc.fascinated.bat.model.beatsaber.scoresaber.*; -import cc.fascinated.bat.model.user.profiles.ScoreSaberProfile; +import cc.fascinated.bat.features.scoresaber.profiles.UserScoreSaberProfile; import com.google.gson.JsonObject; import lombok.NonNull; import lombok.SneakyThrows; @@ -65,7 +65,7 @@ public class ScoreSaberService extends TextWebSocketHandler { * @param page The page to get the scores from. * @return The scores. */ - public ScoreSaberScoresPageToken getPageScores(ScoreSaberProfile profile, int page) { + public ScoreSaberScoresPageToken getPageScores(UserScoreSaberProfile profile, int page) { log.info("Fetching scores for account '{}' from page {}.", profile.getId(), page); ScoreSaberScoresPageToken pageToken = WebRequest.getAsEntity(String.format(GET_PLAYER_SCORES_ENDPOINT, profile.getId(), "recent", page), ScoreSaberScoresPageToken.class); if (pageToken == null) { // Check if the page doesn't exist. @@ -84,7 +84,7 @@ public class ScoreSaberService extends TextWebSocketHandler { * @param profile The profile. * @return The scores. */ - public List getScores(ScoreSaberProfile profile) { + public List getScores(UserScoreSaberProfile profile) { List scores = new ArrayList<>(List.of(getPageScores(profile, 1))); ScoreSaberPageMetadataToken metadata = scores.get(0).getMetadata(); int totalPages = (int) Math.ceil((double) metadata.getTotal() / metadata.getItemsPerPage()); diff --git a/src/main/java/cc/fascinated/bat/service/UserService.java b/src/main/java/cc/fascinated/bat/service/UserService.java index 759ec69..aaec511 100644 --- a/src/main/java/cc/fascinated/bat/service/UserService.java +++ b/src/main/java/cc/fascinated/bat/service/UserService.java @@ -1,6 +1,6 @@ package cc.fascinated.bat.service; -import cc.fascinated.bat.model.user.BatUser; +import cc.fascinated.bat.model.BatUser; import cc.fascinated.bat.repository.UserRepository; import lombok.NonNull; import lombok.extern.log4j.Log4j2;