From a0b3d2167add0be54c3df0361299081a26401c5d Mon Sep 17 00:00:00 2001 From: akastijn Date: Sat, 8 Nov 2025 20:24:07 +0100 Subject: [PATCH] Add `CommandSyncNitro` for synchronizing Nitro roles and update related database queries. --- .../alttd/commandManager/CommandManager.java | 1 + .../commands/CommandSyncNitro.java | 113 ++++++++++++++++++ .../java/com/alttd/config/MessagesConfig.java | 2 + .../database/queries/QueriesUserByRole.java | 42 +++++++ .../queries/QueriesUserDiscordId.java | 34 +++++- 5 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/alttd/commandManager/commands/CommandSyncNitro.java create mode 100644 src/main/java/com/alttd/database/queries/QueriesUserByRole.java diff --git a/src/main/java/com/alttd/commandManager/CommandManager.java b/src/main/java/com/alttd/commandManager/CommandManager.java index a2e194f..3507173 100644 --- a/src/main/java/com/alttd/commandManager/CommandManager.java +++ b/src/main/java/com/alttd/commandManager/CommandManager.java @@ -42,6 +42,7 @@ public class CommandManager extends ListenerAdapter { new CommandHelp(jda, this), new CommandPoll(jda, this, buttonManager), new CommandSuggestion(jda, modalManager, this), + new CommandSyncNitro(jda, this), new CommandSuggestCrateItem(jda, modalManager, this), new CommandSetOutputChannel(jda, this), new CommandUpdateCommands(jda, this), diff --git a/src/main/java/com/alttd/commandManager/commands/CommandSyncNitro.java b/src/main/java/com/alttd/commandManager/commands/CommandSyncNitro.java new file mode 100644 index 0000000..d50eb6a --- /dev/null +++ b/src/main/java/com/alttd/commandManager/commands/CommandSyncNitro.java @@ -0,0 +1,113 @@ +package com.alttd.commandManager.commands; + +import com.alttd.commandManager.CommandManager; +import com.alttd.commandManager.DiscordCommand; +import com.alttd.config.MessagesConfig; +import com.alttd.database.queries.QueriesUserByRole; +import com.alttd.database.queries.QueriesUserDiscordId; +import com.alttd.util.Util; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.InteractionContextType; +import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions; +import net.dv8tion.jda.api.interactions.commands.build.CommandData; +import net.dv8tion.jda.api.interactions.commands.build.Commands; +import net.dv8tion.jda.api.requests.RestAction; +import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class CommandSyncNitro extends DiscordCommand { + + private final CommandData commandData; + private final JDA jda; + + public CommandSyncNitro(JDA jda, CommandManager commandManager) { + this.jda = jda; + commandData = Commands.slash(getName(), "Sync nitro users.") + .setContexts(InteractionContextType.GUILD) + .setDefaultPermissions(DefaultMemberPermissions.DISABLED); + Util.registerCommand(commandManager, jda, commandData, getName()); + } + + @Override + public String getName() { + return "syncnitro"; + } + + @Override + public void execute(SlashCommandInteractionEvent event) { + Guild guildById = jda.getGuildById(141644560005595136L); + if (guildById == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find guild.")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + + ReplyCallbackAction replyCallbackAction = event.deferReply(true); + + QueriesUserByRole.getUserIdsByRole("alpha").thenAcceptAsync(optionalUserIdList -> { + if (optionalUserIdList.isEmpty()) { + replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "No users found.")) + .setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure); + return; + } + checkAllMembers(optionalUserIdList.get(), guildById, replyCallbackAction); + }); + } + + private void checkAllMembers(List userIdList, Guild guildById, ReplyCallbackAction replyCallbackAction) { + ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + + for (int i = 0; i < userIdList.size(); i++) { + long userId = userIdList.get(i); + scheduler.schedule(() -> { + Member member = guildById.getMemberById(userId); + if (member == null) { + guildById.retrieveMemberById(userId) + .queue(retrievedMember -> checkMember(retrievedMember, userId)); + } else { + checkMember(member, userId); + } + }, i, TimeUnit.SECONDS); + } + + replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "Syncing " + userIdList.size() + " users in background")); + + scheduler.shutdown(); + } + + private void checkMember(Member member, long userId) { + if (member == null) { + QueriesUserDiscordId.removeLinkedUserByDiscordId(userId); + return; + } + boolean hasNitro = member.getRoles().stream().anyMatch(role -> role.getIdLong() == 585557866275012633L); + if (!hasNitro) { + QueriesUserDiscordId.removeRole(userId, "nitro"); + } + } + + @Override + public void suggest(CommandAutoCompleteInteractionEvent event) { + event.replyChoices(Collections.emptyList()) + .queue(RestAction.getDefaultSuccess(), Util::handleFailure); + } + + @Override + public String getHelpMessage() { + return MessagesConfig.HELP_SYNC_NITRO; + } + + @Override + public CommandData getCommandData() { + return commandData; + } +} diff --git a/src/main/java/com/alttd/config/MessagesConfig.java b/src/main/java/com/alttd/config/MessagesConfig.java index d2714fc..7b9b871 100644 --- a/src/main/java/com/alttd/config/MessagesConfig.java +++ b/src/main/java/com/alttd/config/MessagesConfig.java @@ -18,11 +18,13 @@ public class MessagesConfig extends AbstractConfig { public static String HELP_SUGGESTION = "`/suggestion`: Opens suggestion form"; public static String HELP_MESSAGE_TEMPLATE = ""; public static String HELP_SEEN = ""; + public static String HELP_SYNC_NITRO = "Syncs the nitro ranks with the minecraft ranks"; private static void loadHelp() { HELP_HELP = messagesConfig.getString("help.help", HELP_HELP); HELP_SUGGESTION = messagesConfig.getString("help.suggestion", HELP_SUGGESTION); HELP_MESSAGE_TEMPLATE = messagesConfig.getString("help.message-template", HELP_MESSAGE_TEMPLATE); HELP_SEEN = messagesConfig.getString("help.seen", HELP_SEEN); + HELP_SYNC_NITRO = messagesConfig.getString("help.sync-alpha", HELP_SYNC_NITRO); } private static void loadPollHelp() { diff --git a/src/main/java/com/alttd/database/queries/QueriesUserByRole.java b/src/main/java/com/alttd/database/queries/QueriesUserByRole.java new file mode 100644 index 0000000..92cf545 --- /dev/null +++ b/src/main/java/com/alttd/database/queries/QueriesUserByRole.java @@ -0,0 +1,42 @@ +package com.alttd.database.queries; + +import com.alttd.database.Database; +import com.alttd.util.Logger; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public class QueriesUserByRole { + + public static CompletableFuture>> getUserIdsByRole(String role) { + String sql = """ + SELECT discord_id + FROM linked_accounts + JOIN account_roles ON linked_accounts.player_uuid = account_roles.uuid + WHERE account_roles.role_name = ?; + """; + return CompletableFuture.supplyAsync(() -> { + try { + PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql); + + preparedStatement.setString(1, role); + ResultSet resultSet = preparedStatement.executeQuery(); + + List discordIds = new ArrayList<>(); + while (resultSet.next()) { + discordIds.add(resultSet.getLong("discord_id")); + } + return Optional.of(discordIds); + } catch (SQLException exception) { + Logger.altitudeLogs.error(exception); + } + return Optional.empty(); + }); + } + +} diff --git a/src/main/java/com/alttd/database/queries/QueriesUserDiscordId.java b/src/main/java/com/alttd/database/queries/QueriesUserDiscordId.java index ae3de1c..6b53fe8 100644 --- a/src/main/java/com/alttd/database/queries/QueriesUserDiscordId.java +++ b/src/main/java/com/alttd/database/queries/QueriesUserDiscordId.java @@ -13,7 +13,7 @@ import java.util.concurrent.CompletableFuture; public class QueriesUserDiscordId { public static CompletableFuture> getUUIDById(long userId) { - String sql = "SELECT player_uuid FROM linked_accounts WHERE discord_id = ?"; + String sql = "SELECT player_uuid FROM linked_accounts WHERE discord_id = ? AND active = true"; return CompletableFuture.supplyAsync(() -> { try { PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql); @@ -30,5 +30,37 @@ public class QueriesUserDiscordId { }); } + public static CompletableFuture removeLinkedUserByDiscordId(long userId) { + String sql = "UPDATE linked_accounts SET active = false WHERE discord_id = ?"; + return CompletableFuture.runAsync(() -> { + try { + PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql); + preparedStatement.setLong(1, userId); + preparedStatement.executeUpdate(); + } catch (SQLException exception) { + Logger.altitudeLogs.error(exception); + } + }); + } + public static void removeRole(long userId, String role) { + String sql = """ + DELETE FROM account_roles + WHERE uuid IN ( + SELECT player_uuid + FROM linked_accounts + WHERE discord_id = ? + ) + AND role_name = ? + """; + + try { + PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql); + preparedStatement.setLong(1, userId); + preparedStatement.setString(2, role); + preparedStatement.executeUpdate(); + } catch (SQLException exception) { + Logger.altitudeLogs.error(exception); + } + } }