From 706ceb4b556db68c219f0270ea0c5bcb77ec0ded Mon Sep 17 00:00:00 2001 From: Teriuihi Date: Sun, 4 Jun 2023 23:30:09 +0200 Subject: [PATCH] Finished poll commands (except for removing a button) added a timer to update total votes every 5 minutes --- .../alttd/buttonManager/ButtonManager.java | 25 +++- .../buttons/pollButton/PollButton.java | 73 ++++++++++ .../alttd/commandManager/CommandManager.java | 5 +- .../commands/PollCommand/CommandPoll.java | 9 +- .../commands/PollCommand/PollChannel.java | 8 + .../commands/PollCommand/PollUtil.java | 81 +++++++++++ .../commands/PollCommand/Polls.java | 32 ---- .../commands/PollCommand/SubCommandAdd.java | 6 +- .../PollCommand/SubCommandAddButton.java | 82 +++++++---- .../commands/PollCommand/SubCommandClose.java | 37 +++-- .../SubCommandEditDescription.java | 23 ++- .../PollCommand/SubCommandEditTitle.java | 23 ++- .../commands/PollCommand/SubCommandOpen.java | 46 ++++-- .../PollCommand/SubCommandRemoveButton.java | 21 ++- .../PollCommand/SubCommandResults.java | 12 +- .../com/alttd/database/queries/Poll/Poll.java | 137 ++++++++++++++++++ .../queries/Poll/PollButtonClicksQueries.java | 63 ++++++++ .../queries/Poll/PollButtonQueries.java | 60 ++++++++ .../database/queries/Poll/PollQueries.java | 72 +++++++++ .../java/com/alttd/listeners/JDAListener.java | 9 +- .../com/alttd/schedulers/PollTimerTask.java | 69 +++++++++ 21 files changed, 750 insertions(+), 143 deletions(-) create mode 100644 src/main/java/com/alttd/buttonManager/buttons/pollButton/PollButton.java create mode 100644 src/main/java/com/alttd/commandManager/commands/PollCommand/PollChannel.java create mode 100644 src/main/java/com/alttd/commandManager/commands/PollCommand/PollUtil.java delete mode 100644 src/main/java/com/alttd/commandManager/commands/PollCommand/Polls.java create mode 100644 src/main/java/com/alttd/database/queries/Poll/Poll.java create mode 100644 src/main/java/com/alttd/database/queries/Poll/PollButtonClicksQueries.java create mode 100644 src/main/java/com/alttd/database/queries/Poll/PollButtonQueries.java create mode 100644 src/main/java/com/alttd/database/queries/Poll/PollQueries.java create mode 100644 src/main/java/com/alttd/schedulers/PollTimerTask.java diff --git a/src/main/java/com/alttd/buttonManager/ButtonManager.java b/src/main/java/com/alttd/buttonManager/ButtonManager.java index 977d15d..3ee151f 100644 --- a/src/main/java/com/alttd/buttonManager/ButtonManager.java +++ b/src/main/java/com/alttd/buttonManager/ButtonManager.java @@ -17,6 +17,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.awt.*; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -25,14 +26,22 @@ public class ButtonManager extends ListenerAdapter { private final List buttons; public ButtonManager() { - buttons = List.of( - new ButtonSuggestionReviewAccept(), - new ButtonSuggestionReviewDeny(), - new ButtonRemindMeCancel(), - new ButtonRemindMeConfirm(), - new ButtonAccepted(), - new ButtonInProgress(), - new ButtonRejected()); + buttons = new ArrayList<>(); + buttons.add(new ButtonSuggestionReviewAccept()); + buttons.add(new ButtonSuggestionReviewDeny()); + buttons.add(new ButtonRemindMeCancel()); + buttons.add(new ButtonRemindMeConfirm()); + buttons.add(new ButtonAccepted()); + buttons.add(new ButtonInProgress()); + buttons.add(new ButtonRejected()); + } + + public void addButton(DiscordButton button) { + buttons.add(button); + } + + public void removeButton(DiscordButton button) { + } @Override diff --git a/src/main/java/com/alttd/buttonManager/buttons/pollButton/PollButton.java b/src/main/java/com/alttd/buttonManager/buttons/pollButton/PollButton.java new file mode 100644 index 0000000..8eefe33 --- /dev/null +++ b/src/main/java/com/alttd/buttonManager/buttons/pollButton/PollButton.java @@ -0,0 +1,73 @@ +package com.alttd.buttonManager.buttons.pollButton; + +import com.alttd.buttonManager.DiscordButton; +import com.alttd.database.queries.Poll.Poll; +import com.alttd.database.queries.Poll.PollButtonClicksQueries; +import com.alttd.util.Util; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.interactions.components.buttons.Button; + +import java.util.HashSet; + +public class PollButton extends DiscordButton { + + private final long internalId; + private final String buttonId; + private final String buttonTitle; + private final HashSet userClicks; + + public PollButton(long internalId, String buttonId, String buttonTitle, HashSet userClicks) { + this.internalId = internalId; + this.buttonId = buttonId; + this.buttonTitle = buttonTitle; + this.userClicks = userClicks; + } + + @Override + public String getButtonId() { + return buttonId; + } + + @Override + public void execute(ButtonInteractionEvent event) { + long userId = event.getUser().getIdLong(); + Poll poll = Poll.getPoll(event.getMessage().getIdLong()); + if (!poll.isActive()) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to process your vote for " + buttonTitle + ", the poll might have ended!")).setEphemeral(true).queue(); + return; + } + if (userClicks.contains(userId)) { + PollButtonClicksQueries.removeButtonClick(poll.getPollId(), userId); + userClicks.remove(userId); + poll.receivedVote(); + event.replyEmbeds(Util.genericSuccessEmbed("Success", "Removed your vote from " + buttonTitle + ", thanks!")).setEphemeral(true).queue(); + return; + } + poll.resetClicks(userId); + PollButtonClicksQueries.addButtonClick(poll.getPollId(), internalId, userId); + userClicks.add(userId); + poll.receivedVote(); + event.replyEmbeds(Util.genericSuccessEmbed("Success", "You voted on " + buttonTitle + ", thanks!")).setEphemeral(true).queue(); + } + + @Override + public Button getButton() { + return Button.primary(getButtonId(), buttonTitle); + } + + public long getInternalId() { + return internalId; + } + + public void removeClick(long userId) { + userClicks.remove(userId); + } + + public String getButtonTitle() { + return buttonTitle; + } + + public int getVotes() { + return userClicks.size(); + } +} diff --git a/src/main/java/com/alttd/commandManager/CommandManager.java b/src/main/java/com/alttd/commandManager/CommandManager.java index 6d95d30..410edcd 100644 --- a/src/main/java/com/alttd/commandManager/CommandManager.java +++ b/src/main/java/com/alttd/commandManager/CommandManager.java @@ -1,5 +1,6 @@ package com.alttd.commandManager; +import com.alttd.buttonManager.ButtonManager; import com.alttd.commandManager.commands.AddCommand.CommandManage; import com.alttd.commandManager.commands.*; import com.alttd.commandManager.commands.PollCommand.CommandPoll; @@ -30,7 +31,7 @@ public class CommandManager extends ListenerAdapter { private final List commands; private final HashMap> commandList = new HashMap<>(); - public CommandManager(JDA jda, ModalManager modalManager, ContextMenuManager contextMenuManager, LockedChannel lockedChannel, SelectMenuManager selectMenuManager) { + public CommandManager(JDA jda, ModalManager modalManager, ContextMenuManager contextMenuManager, LockedChannel lockedChannel, SelectMenuManager selectMenuManager, ButtonManager buttonManager) { commandList.put("manage", new ArrayList<>(List.of(new ScopeInfo(CommandScope.GLOBAL, 0)))); loadCommands(); Logger.altitudeLogs.info("Loading commands..."); @@ -38,7 +39,7 @@ public class CommandManager extends ListenerAdapter { commands = List.of( new CommandManage(jda, this, contextMenuManager), new CommandHelp(jda, this), - new CommandPoll(jda, this), + new CommandPoll(jda, this, buttonManager), new CommandSuggestion(jda, modalManager, this), new CommandSuggestCrateItem(jda, modalManager, this), new CommandSetOutputChannel(jda, this), diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/CommandPoll.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/CommandPoll.java index 5d516cb..9005f7f 100644 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/CommandPoll.java +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/CommandPoll.java @@ -1,5 +1,6 @@ package com.alttd.commandManager.commands.PollCommand; +import com.alttd.buttonManager.ButtonManager; import com.alttd.commandManager.CommandManager; import com.alttd.commandManager.DiscordCommand; import com.alttd.commandManager.SubOption; @@ -22,7 +23,7 @@ public class CommandPoll extends DiscordCommand { private final HashMap subOptionsMap = new HashMap<>(); private final CommandData commandData; - public CommandPoll(JDA jda, CommandManager commandManager) { + public CommandPoll(JDA jda, CommandManager commandManager, ButtonManager buttonManager) { commandData = Commands.slash(getName(), "Create, edit, and manage polls") .addSubcommands( new SubcommandData("add", "Add a new poll to a channel") @@ -58,11 +59,11 @@ public class CommandPoll extends DiscordCommand { .setGuildOnly(true); Util.registerSubOptions(subOptionsMap, new SubCommandAdd(null,this), - new SubCommandAddButton(null, this), - new SubCommandClose(null,this), + new SubCommandAddButton(null, this, buttonManager), + new SubCommandClose(null,this, buttonManager), new SubCommandEditDescription(null, this), new SubCommandEditTitle(null, this), - new SubCommandOpen(null, this), + new SubCommandOpen(null, this, buttonManager), new SubCommandRemoveButton(null, this), new SubCommandResults(null,this)); Util.registerCommand(commandManager, jda, commandData, getName()); diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/PollChannel.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/PollChannel.java new file mode 100644 index 0000000..00799d2 --- /dev/null +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/PollChannel.java @@ -0,0 +1,8 @@ +package com.alttd.commandManager.commands.PollCommand; + +import com.alttd.database.queries.Poll.Poll; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; + +public record PollChannel(Poll poll, TextChannel textChannel) { + +} diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/PollUtil.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/PollUtil.java new file mode 100644 index 0000000..244e2b4 --- /dev/null +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/PollUtil.java @@ -0,0 +1,81 @@ +package com.alttd.commandManager.commands.PollCommand; + +import com.alttd.database.queries.Poll.Poll; +import com.alttd.util.OptionMappingParsing; +import com.alttd.util.Util; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; +import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.AutoCompleteQuery; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class PollUtil { + + protected static PollChannel getPollHandleErrors(SlashCommandInteractionEvent event, String name) { + Long messageId = Util.parseLong(OptionMappingParsing.getString("message_id", event, name)); + if (messageId == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid message id")).setEphemeral(true).queue(); + return null; + } + + Poll poll = Poll.getPoll(messageId); + if (poll == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "There is no poll with this message id")).setEphemeral(true).queue(); + return null; + } + + Guild guild = event.getGuild(); + if (guild == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "There is no guild for this event")).setEphemeral(true).queue(); + return null; + } + + TextChannel textChannel = guild.getTextChannelById(poll.getChannelId()); + if (textChannel == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Cannot find the poll channel")).setEphemeral(true).queue(); + return null; + } + + if (!textChannel.canTalk()) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "I cannot talk in this channel")).setEphemeral(true).queue(); + return null; + } + + Member member = event.getMember(); + if (member == null) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "Cannot find you as a member")).setEphemeral(true).queue(); + return null; + } + + if (!textChannel.canTalk(member)) { + event.replyEmbeds(Util.genericErrorEmbed("Error", "You cannot talk in this channel")).setEphemeral(true).queue(); + return null; + } + return new PollChannel(poll, textChannel); + } + + protected static void handleSuggestMessageId(CommandAutoCompleteInteractionEvent event) { + Guild guild = event.getGuild(); + if (guild == null) { + event.replyChoices(new ArrayList<>()).queue(); + return; + } + AutoCompleteQuery focusedOption = event.getFocusedOption(); + if (focusedOption.getName().equals("message_id")) { + List guildPolls = Poll.getGuildPolls(event.getGuild().getIdLong()); + try { + String value = focusedOption.getValue(); + event.replyChoiceLongs(guildPolls.stream().map(Poll::getPollId).filter(pollId -> String.valueOf(pollId).startsWith(value)).collect(Collectors.toList())).queue(); + } catch (NumberFormatException ignored) { + event.replyChoices(new ArrayList<>()).queue(); + } + } + } + +} + diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/Polls.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/Polls.java deleted file mode 100644 index 2c48986..0000000 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/Polls.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.alttd.commandManager.commands.PollCommand; - -import java.util.HashMap; - -public class Polls { - - private static Polls instance = null; - private HashMap pollDataMap; - - private Polls() { - pollDataMap = new HashMap<>(); - //TODO load poll data - } - - public static Polls getInstance() { - if (instance == null) - instance = new Polls(); - return instance; - } - - public boolean addPoll(long pollId, PollData pollData) { - if (pollDataMap.containsKey(pollId)) - return (false); - pollDataMap.put(pollId, pollData); - return true; - } - - public PollData getPoll(long pollId) { - return pollDataMap.getOrDefault(pollId, null); - } - -} diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandAdd.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandAdd.java index 8a5ad84..08fcfaf 100644 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandAdd.java +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandAdd.java @@ -3,6 +3,7 @@ package com.alttd.commandManager.commands.PollCommand; import com.alttd.commandManager.DiscordCommand; import com.alttd.commandManager.SubCommand; import com.alttd.commandManager.SubCommandGroup; +import com.alttd.database.queries.Poll.PollQueries; import com.alttd.templates.Parser; import com.alttd.templates.Template; import com.alttd.util.Logger; @@ -71,10 +72,11 @@ public class SubCommandAdd extends SubCommand { .setTitle(title) .setColor(Color.RED) .build() - ).queue(message -> createdPoll(message, hook), throwable -> failedCreatingPoll(throwable, hook)); + ).queue(message -> createdPoll(message, title, hook), throwable -> failedCreatingPoll(throwable, hook)); } - private void createdPoll(Message message, InteractionHook hook) { + private void createdPoll(Message message, String title, InteractionHook hook) { + PollQueries.addPoll(message.getIdLong(), message.getChannel().getIdLong(), message.getGuild().getIdLong(), title); hook.editOriginalEmbeds(Util.genericSuccessEmbed("Created Poll!", Parser.parse("Created a poll with the message id: ``. " + "When you're ready don't forget to open the poll!", diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandAddButton.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandAddButton.java index 69182ea..7b2d7ea 100644 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandAddButton.java +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandAddButton.java @@ -1,24 +1,33 @@ package com.alttd.commandManager.commands.PollCommand; +import com.alttd.buttonManager.ButtonManager; +import com.alttd.buttonManager.buttons.pollButton.PollButton; import com.alttd.commandManager.DiscordCommand; import com.alttd.commandManager.SubCommand; import com.alttd.commandManager.SubCommandGroup; +import com.alttd.database.queries.Poll.Poll; +import com.alttd.database.queries.Poll.PollButtonQueries; import com.alttd.templates.Parser; import com.alttd.templates.Template; import com.alttd.util.Logger; import com.alttd.util.OptionMappingParsing; import com.alttd.util.Util; -import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.channel.ChannelType; -import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.InteractionHook; +import net.dv8tion.jda.api.interactions.components.ActionRow; +import net.dv8tion.jda.api.interactions.components.ItemComponent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; public class SubCommandAddButton extends SubCommand { - protected SubCommandAddButton(SubCommandGroup parentGroup, DiscordCommand parent) { + private final ButtonManager buttonManager; + protected SubCommandAddButton(SubCommandGroup parentGroup, DiscordCommand parent, ButtonManager buttonManager) { super(parentGroup, parent); + this.buttonManager = buttonManager; } @Override @@ -28,23 +37,9 @@ public class SubCommandAddButton extends SubCommand { @Override public void execute(SlashCommandInteractionEvent event) { - GuildMessageChannel channel = OptionMappingParsing.getGuildChannel("channel", event, getName()); - Member member = event.getMember(); - if (member == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find valid guild member.")) - .setEphemeral(true) - .queue(); + PollChannel pollChannel = PollUtil.getPollHandleErrors(event, getName()); + if (pollChannel == null) return; - } - if (!Util.validateGuildMessageChannel(event.getInteraction(), channel, ChannelType.TEXT, member)) - return; - - Long messageId = Util.parseLong(OptionMappingParsing.getString("message_id", event, getName())); - if (messageId == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid message id")).setEphemeral(true).queue(); - return; - } - //TODO verify that message id is in database Long rowLong = Util.parseLong(OptionMappingParsing.getString("button_row", event, getName())); if (rowLong == null) { @@ -63,6 +58,7 @@ public class SubCommandAddButton extends SubCommand { .queue(); return; } + String buttonName = OptionMappingParsing.getString("button_name", event, getName()); if (buttonName == null) { event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to retrieve button name.")) @@ -70,15 +66,16 @@ public class SubCommandAddButton extends SubCommand { .queue(); return; } + event.deferReply(true).queue(hook -> - channel.retrieveMessageById(messageId).queue( - message -> updatePoll(channel, rowId, buttonName, message, hook), + pollChannel.textChannel().retrieveMessageById(pollChannel.poll().getPollId()).queue( + message -> updatePoll(rowId, buttonName, message, hook), throwable -> failedToGetMessage(throwable, hook))); } @Override public void suggest(CommandAutoCompleteInteractionEvent event) { - + PollUtil.handleSuggestMessageId(event); } private void failedToGetMessage(Throwable throwable, InteractionHook hook) { @@ -88,11 +85,40 @@ public class SubCommandAddButton extends SubCommand { .queue(); } - private void updatePoll(GuildMessageChannel channel, int rowId, String buttonName, Message message, - InteractionHook hook) { - //TODO add button, generate id, add a way to remove button, store id in database - //Maybe temporarily disable the poll and listen for someone to click the button, then delete that button - // and switch back to normal poll mode? + private void updatePoll(int rowId, String buttonName, Message message, InteractionHook hook) { + String buttonId = message.getId() + buttonName; + Poll poll = Poll.getPoll(message.getIdLong()); + PollButtonQueries.addButton(message.getIdLong(), buttonId, buttonName); + List pollButtons = PollButtonQueries.loadButtons(poll, buttonManager); + if (pollButtons == null) { + hook.editOriginalEmbeds(Util.genericErrorEmbed("Error","Unable to retrieve buttons for this poll")).queue(); + return; + } + + Optional any = pollButtons.stream().filter(button -> button.getButtonId().equals(buttonId)).findAny(); + if (any.isEmpty()) { + hook.editOriginalEmbeds(Util.genericErrorEmbed("Error", "Unable to find newly created button")).queue(); + return; + } + + PollButton pollButton = any.get(); + List actionRows = message.getActionRows(); + if (rowId > 1) {//todo fix if needed in the future + hook.editOriginalEmbeds(Util.genericErrorEmbed("Error", + "Polls have only been set up to handle 1 row if you need more than one row update the code.")) + .queue(); + return; + } + + List components; + if (!actionRows.isEmpty()) { + components = actionRows.get(0).getComponents(); + } else + components = new ArrayList<>(); + + components.add(pollButton.getButton()); + message.editMessageComponents().setActionRow(components).queue(); + hook.editOriginalEmbeds(Util.genericSuccessEmbed("Success", "Added a button")).queue(); } @Override diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandClose.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandClose.java index 85fc754..552cf3f 100644 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandClose.java +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandClose.java @@ -1,17 +1,26 @@ package com.alttd.commandManager.commands.PollCommand; +import com.alttd.buttonManager.ButtonManager; import com.alttd.commandManager.DiscordCommand; import com.alttd.commandManager.SubCommand; import com.alttd.commandManager.SubCommandGroup; -import com.alttd.util.OptionMappingParsing; +import com.alttd.database.queries.Poll.Poll; +import com.alttd.database.queries.Poll.PollQueries; import com.alttd.util.Util; -import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; + +import java.util.List; public class SubCommandClose extends SubCommand { - protected SubCommandClose(SubCommandGroup parentGroup, DiscordCommand parent) { + + private final ButtonManager buttonManager; + protected SubCommandClose(SubCommandGroup parentGroup, DiscordCommand parent, ButtonManager buttonManager) { super(parentGroup, parent); + this.buttonManager = buttonManager; } @Override @@ -21,22 +30,28 @@ public class SubCommandClose extends SubCommand { @Override public void execute(SlashCommandInteractionEvent event) { - GuildMessageChannel channel = OptionMappingParsing.getGuildChannel("channel", event, getName()); - if (channel == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid channel")).setEphemeral(true).queue(); + PollChannel pollChannel = PollUtil.getPollHandleErrors(event, getName()); + if (pollChannel == null) return; - } + Poll poll = pollChannel.poll(); + ReplyCallbackAction replyCallbackAction = event.deferReply(true); + pollChannel.textChannel().retrieveMessageById(poll.getPollId()).queue(message -> closePoll(message, poll, replyCallbackAction)); + } - Long messageId = Util.parseLong(OptionMappingParsing.getString("message_id", event, getName())); - if (messageId == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid message id")).setEphemeral(true).queue(); + private void closePoll(Message message, Poll poll, ReplyCallbackAction replyCallbackAction) { + List embeds = message.getEmbeds(); + if (embeds.size() > 1) { + replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "This poll has already been closed!")).queue(); return; } + message.editMessageEmbeds(embeds.get(0), poll.getVotesEmbed()).queue(); + PollQueries.setPollStatus(poll.getPollId(), false, buttonManager); + replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "This poll has been closed!")).queue(); } @Override public void suggest(CommandAutoCompleteInteractionEvent event) { - + PollUtil.handleSuggestMessageId(event); } @Override diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandEditDescription.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandEditDescription.java index a5b67dc..14f1111 100644 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandEditDescription.java +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandEditDescription.java @@ -3,16 +3,21 @@ package com.alttd.commandManager.commands.PollCommand; import com.alttd.commandManager.DiscordCommand; import com.alttd.commandManager.SubCommand; import com.alttd.commandManager.SubCommandGroup; +import com.alttd.database.queries.Poll.Poll; import com.alttd.util.OptionMappingParsing; import com.alttd.util.Util; import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.AutoCompleteQuery; import net.dv8tion.jda.api.interactions.InteractionHook; import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; public class SubCommandEditDescription extends SubCommand { protected SubCommandEditDescription(SubCommandGroup parentGroup, DiscordCommand parent) { @@ -26,17 +31,9 @@ public class SubCommandEditDescription extends SubCommand { @Override public void execute(SlashCommandInteractionEvent event) { - GuildMessageChannel channel = OptionMappingParsing.getGuildChannel("channel", event, getName()); - if (channel == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid channel")).setEphemeral(true).queue(); + PollChannel pollChannel = PollUtil.getPollHandleErrors(event, getName()); + if (pollChannel == null) return; - } - - Long messageId = Util.parseLong(OptionMappingParsing.getString("message_id", event, getName())); - if (messageId == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid message id")).setEphemeral(true).queue(); - return; - } String description = OptionMappingParsing.getString("description", event, getName()); if (description == null || description.length() > 2048) { @@ -48,8 +45,8 @@ public class SubCommandEditDescription extends SubCommand { } event.replyEmbeds(Util.genericWaitingEmbed("Waiting...", "Editing poll...")).setEphemeral(true).queue(hook -> { - channel.retrieveMessageById(messageId).queue(message -> updatePoll(message, description, hook), - error -> hook.editOriginalEmbeds(Util.genericErrorEmbed("Error", "Unable to find message with id [" + messageId + "].")).queue()); + pollChannel.textChannel().retrieveMessageById(pollChannel.poll().getPollId()).queue(message -> updatePoll(message, description, hook), + error -> hook.editOriginalEmbeds(Util.genericErrorEmbed("Error", "Unable to find message with id [" + pollChannel.poll().getPollId() + "].")).queue()); }); } @@ -67,7 +64,7 @@ public class SubCommandEditDescription extends SubCommand { @Override public void suggest(CommandAutoCompleteInteractionEvent event) { - event.replyChoices(new ArrayList<>()).queue(); + PollUtil.handleSuggestMessageId(event); } @Override diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandEditTitle.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandEditTitle.java index 212fe84..c4793ec 100644 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandEditTitle.java +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandEditTitle.java @@ -3,16 +3,21 @@ package com.alttd.commandManager.commands.PollCommand; import com.alttd.commandManager.DiscordCommand; import com.alttd.commandManager.SubCommand; import com.alttd.commandManager.SubCommandGroup; +import com.alttd.database.queries.Poll.Poll; import com.alttd.util.OptionMappingParsing; import com.alttd.util.Util; import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.AutoCompleteQuery; import net.dv8tion.jda.api.interactions.InteractionHook; import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; public class SubCommandEditTitle extends SubCommand { protected SubCommandEditTitle(SubCommandGroup parentGroup, DiscordCommand parent) { @@ -26,17 +31,9 @@ public class SubCommandEditTitle extends SubCommand { @Override public void execute(SlashCommandInteractionEvent event) { - GuildMessageChannel channel = OptionMappingParsing.getGuildChannel("channel", event, getName()); - if (channel == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid channel")).setEphemeral(true).queue(); + PollChannel pollChannel = PollUtil.getPollHandleErrors(event, getName()); + if (pollChannel == null) return; - } - - Long messageId = Util.parseLong(OptionMappingParsing.getString("message_id", event, getName())); - if (messageId == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid message id")).setEphemeral(true).queue(); - return; - } String title = OptionMappingParsing.getString("title", event, getName()); if (title == null || title.length() > 256) { @@ -48,8 +45,8 @@ public class SubCommandEditTitle extends SubCommand { } event.replyEmbeds(Util.genericWaitingEmbed("Waiting...", "Editing poll...")).setEphemeral(true).queue(hook -> { - channel.retrieveMessageById(messageId).queue(message -> updatePoll(message, title, hook), - error -> hook.editOriginalEmbeds(Util.genericErrorEmbed("Error", "Unable to find message with id [" + messageId + "].")).queue()); + pollChannel.textChannel().retrieveMessageById(pollChannel.poll().getPollId()).queue(message -> updatePoll(message, title, hook), + error -> hook.editOriginalEmbeds(Util.genericErrorEmbed("Error", "Unable to find message with id [" + pollChannel.poll().getPollId() + "].")).queue()); }); } @@ -67,7 +64,7 @@ public class SubCommandEditTitle extends SubCommand { @Override public void suggest(CommandAutoCompleteInteractionEvent event) { - event.replyChoices(new ArrayList<>()).queue(); + PollUtil.handleSuggestMessageId(event); } @Override diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandOpen.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandOpen.java index f8a514f..38bda79 100644 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandOpen.java +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandOpen.java @@ -1,17 +1,33 @@ package com.alttd.commandManager.commands.PollCommand; +import com.alttd.buttonManager.ButtonManager; import com.alttd.commandManager.DiscordCommand; import com.alttd.commandManager.SubCommand; import com.alttd.commandManager.SubCommandGroup; +import com.alttd.database.queries.Poll.Poll; +import com.alttd.database.queries.Poll.PollQueries; import com.alttd.util.OptionMappingParsing; import com.alttd.util.Util; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import net.dv8tion.jda.api.interactions.AutoCompleteQuery; +import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; public class SubCommandOpen extends SubCommand { - protected SubCommandOpen(SubCommandGroup parentGroup, DiscordCommand parent) { + private final ButtonManager buttonManager; + protected SubCommandOpen(SubCommandGroup parentGroup, DiscordCommand parent, ButtonManager buttonManager) { super(parentGroup, parent); + this.buttonManager = buttonManager; } @Override @@ -21,22 +37,34 @@ public class SubCommandOpen extends SubCommand { @Override public void execute(SlashCommandInteractionEvent event) { - GuildMessageChannel channel = OptionMappingParsing.getGuildChannel("channel", event, getName()); - if (channel == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid channel")).setEphemeral(true).queue(); + PollChannel pollChannel = PollUtil.getPollHandleErrors(event, getName()); + if (pollChannel == null) return; - } + ReplyCallbackAction replyCallbackAction = event.deferReply(true); + pollChannel.textChannel().retrieveMessageById(pollChannel.poll().getPollId()).queue(a -> openPoll(a, replyCallbackAction)); + } - Long messageId = Util.parseLong(OptionMappingParsing.getString("message_id", event, getName())); - if (messageId == null) { - event.replyEmbeds(Util.genericErrorEmbed("Error", "Invalid message id")).setEphemeral(true).queue(); + + private void openPoll(Message message, ReplyCallbackAction replyCallbackAction) { + boolean res = PollQueries.setPollStatus(message.getIdLong(), true, buttonManager); + if (!res) { + replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "Could not open poll in database")).queue(); return; } + List embeds = message.getEmbeds(); + if (embeds.isEmpty()) { + replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "Could not find poll embed")).queue(); + return; + } + MessageEmbed messageEmbed = embeds.get(0); + EmbedBuilder embedBuilder = new EmbedBuilder(messageEmbed); + embedBuilder.setColor(Color.GREEN); + message.editMessageEmbeds(embedBuilder.build()).queue(success -> replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "Poll opened")).queue()); } @Override public void suggest(CommandAutoCompleteInteractionEvent event) { - + PollUtil.handleSuggestMessageId(event); } @Override diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandRemoveButton.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandRemoveButton.java index 39ec9ee..880916e 100644 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandRemoveButton.java +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandRemoveButton.java @@ -3,8 +3,7 @@ package com.alttd.commandManager.commands.PollCommand; import com.alttd.commandManager.DiscordCommand; import com.alttd.commandManager.SubCommand; import com.alttd.commandManager.SubCommandGroup; -import com.alttd.util.OptionMappingParsing; -import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; +import com.alttd.util.Util; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; @@ -20,20 +19,18 @@ public class SubCommandRemoveButton extends SubCommand { @Override public void execute(SlashCommandInteractionEvent event) { - GuildMessageChannel channel = OptionMappingParsing.getGuildChannel("channel", event, getName()); - if (channel == null) - return; - Long messageId = OptionMappingParsing.getLong("message_id", event, getName()); - if (messageId == null) - return; - String buttonName = OptionMappingParsing.getString("button_name", event, getName()); - if (buttonName == null) - return; + event.replyEmbeds(Util.genericErrorEmbed("Error", "The code to remove buttons was never implemented")).setEphemeral(true).queue(); +// PollChannel pollChannel = PollUtil.getPollHandleErrors(event, getName()); +// if (pollChannel == null) +// return; +// String buttonName = OptionMappingParsing.getString("button_name", event, getName()); +// if (buttonName == null) +// return; } @Override public void suggest(CommandAutoCompleteInteractionEvent event) { - + PollUtil.handleSuggestMessageId(event); } @Override diff --git a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandResults.java b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandResults.java index ce42e79..f976dd3 100644 --- a/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandResults.java +++ b/src/main/java/com/alttd/commandManager/commands/PollCommand/SubCommandResults.java @@ -3,8 +3,6 @@ package com.alttd.commandManager.commands.PollCommand; import com.alttd.commandManager.DiscordCommand; import com.alttd.commandManager.SubCommand; import com.alttd.commandManager.SubCommandGroup; -import com.alttd.util.OptionMappingParsing; -import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; @@ -20,17 +18,15 @@ public class SubCommandResults extends SubCommand { @Override public void execute(SlashCommandInteractionEvent event) { - GuildMessageChannel channel = OptionMappingParsing.getGuildChannel("channel", event, getName()); - if (channel == null) - return; - Long messageId = OptionMappingParsing.getLong("message_id", event, getName()); - if (messageId == null) + PollChannel pollChannel = PollUtil.getPollHandleErrors(event, getName()); + if (pollChannel == null) return; + event.replyEmbeds(pollChannel.poll().getVotesEmbed()).setEphemeral(true).queue(); } @Override public void suggest(CommandAutoCompleteInteractionEvent event) { - + PollUtil.handleSuggestMessageId(event); } @Override diff --git a/src/main/java/com/alttd/database/queries/Poll/Poll.java b/src/main/java/com/alttd/database/queries/Poll/Poll.java new file mode 100644 index 0000000..9591e2b --- /dev/null +++ b/src/main/java/com/alttd/database/queries/Poll/Poll.java @@ -0,0 +1,137 @@ +package com.alttd.database.queries.Poll; + +import com.alttd.buttonManager.buttons.pollButton.PollButton; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.entities.MessageEmbed; + +import java.awt.*; +import java.util.*; +import java.util.List; +import java.util.stream.Collectors; + +public class Poll { + + private static final HashMap polls = new HashMap<>(); + public static Poll getPoll(long pollId) { + return polls.get(pollId); + } + + public static List getGuildPolls(long guildId) { + return polls.values().stream().filter(poll -> poll.getGuildId() == guildId).collect(Collectors.toList()); + } + + public static Collection getAllPolls() { + return polls.values(); + } + + private static void addPoll(Poll poll) { + polls.put(poll.getPollId(), poll); + } + + private final long pollId; + private final long channelId; + private final long guildId; + private boolean active; + private String title; + private final List buttons = new ArrayList<>(); + private boolean needsUpdate = false; + + + public Poll(long pollId, long channelId, long guildId, boolean active, String title) { + this.pollId = pollId; + this.channelId = channelId; + this.guildId = guildId; + this.active = active; + this.title = title; + Poll.addPoll(this); + } + + public void setTitle(String title) { + this.title = title; + } + + public void resetClicks(long userId) { + for (PollButton button : buttons) { + button.removeClick(userId); + } + } + + public void addButton(PollButton button) { + if (buttons.stream() + .filter(listButton -> listButton.getButtonId().equals(button.getButtonId())) + .findAny() + .isEmpty()) + buttons.add(button); + } + + public void addButtons(List buttons) { + buttons.forEach(this::addButton); + } + + public void removeButton(PollButton button) { + buttons.remove(button); + } + + public long getPollId() { + return pollId; + } + + public long getChannelId() { + return channelId; + } + + public long getGuildId() { + return guildId; + } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } + public String getTitle() { + return title; + } + + public PollButton getButton(long internalId) { + return buttons.stream().filter(button -> button.getInternalId() == internalId).findAny().orElse(null); + } + + public MessageEmbed getVotesEmbed() { + EmbedBuilder embedBuilder = new EmbedBuilder(); + embedBuilder + .setColor(Color.GREEN) + .setTitle(getEmbedTitle()); + buttons.sort(Comparator.comparingLong(PollButton::getInternalId)); + for (PollButton button : buttons) { + embedBuilder.addField(button.getButtonTitle(), String.valueOf(button.getVotes()), true); + } + + return embedBuilder.build(); + } + + private String getEmbedTitle() { + String embedTitle = "Results for: " + title; + if (embedTitle.length() > MessageEmbed.TITLE_MAX_LENGTH) + embedTitle = embedTitle.substring(0, MessageEmbed.TITLE_MAX_LENGTH - 3) + "..."; + return embedTitle; + } + + public boolean needsUpdate() { + return needsUpdate; + } + + public void receivedVote() { + needsUpdate = true; + } + + public void setUpdated() { + needsUpdate = false; + } + + public long getTotalVotes() { + return buttons.stream().map(PollButton::getVotes).count(); + } +} diff --git a/src/main/java/com/alttd/database/queries/Poll/PollButtonClicksQueries.java b/src/main/java/com/alttd/database/queries/Poll/PollButtonClicksQueries.java new file mode 100644 index 0000000..efcf9bf --- /dev/null +++ b/src/main/java/com/alttd/database/queries/Poll/PollButtonClicksQueries.java @@ -0,0 +1,63 @@ +package com.alttd.database.queries.Poll; + +import com.alttd.database.Database; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.HashSet; + +public class PollButtonClicksQueries { + + public static boolean addButtonClick(long pollId, long buttonId, long userId) { + String sql = "INSERT INTO poll_entries (poll_id, button_id, user_id) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE button_id = ?"; + try { + PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); + statement.setLong(1, pollId); + statement.setLong(2, buttonId); + statement.setLong(3, userId); + statement.setLong(4, buttonId); + + return statement.execute(); + } catch (SQLException exception) { + exception.printStackTrace(); + } + return false; + } + + public static boolean removeButtonClick(long pollId, long userId) { + String sql = "DELETE FROM poll_entries WHERE poll_id = ? AND user_id = ?"; + try { + PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); + statement.setLong(1, pollId); + statement.setLong(2, userId); + + return statement.execute(); + } catch (SQLException exception) { + exception.printStackTrace(); + } + return false; + } + + public static HashMap> loadClicks(long pollId) { + String sql = "SELECT button_id,user_id FROM poll_entries WHERE poll_id = ?"; + HashMap> buttonMap = new HashMap<>(); + try { + PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); + statement.setLong(1, pollId); + + ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + Long buttonId = resultSet.getLong("button_id"); + HashSet userSet = buttonMap.getOrDefault(buttonId, new HashSet<>()); + userSet.add(resultSet.getLong("user_id")); + buttonMap.put(buttonId, userSet); + } + return buttonMap; + } catch (SQLException exception) { + exception.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/com/alttd/database/queries/Poll/PollButtonQueries.java b/src/main/java/com/alttd/database/queries/Poll/PollButtonQueries.java new file mode 100644 index 0000000..56cd3f5 --- /dev/null +++ b/src/main/java/com/alttd/database/queries/Poll/PollButtonQueries.java @@ -0,0 +1,60 @@ +package com.alttd.database.queries.Poll; + +import com.alttd.buttonManager.ButtonManager; +import com.alttd.buttonManager.buttons.pollButton.PollButton; +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.HashMap; +import java.util.HashSet; +import java.util.List; + +public class PollButtonQueries { + + public static boolean addButton(long pollId, String buttonId, String buttonName/*TODO: , String buttonType*/) { + String sql = "INSERT INTO poll_buttons (poll_id, button_id, button_name, button_type) VALUES (?, ?, ?, ?)"; + try { + PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); + statement.setLong(1, pollId); + statement.setString(2, buttonId); + statement.setString(3, buttonName); + statement.setString(4, "POLL_BUTTON"); //TODO make this change to the other thing too? + + return statement.execute(); + } catch (SQLException exception) { + exception.printStackTrace(); + } + return false; + } + + public static List loadButtons(Poll poll, ButtonManager buttonManager) { + HashMap> userClicks = PollButtonClicksQueries.loadClicks(poll.getPollId()); + if (userClicks == null) { + Logger.altitudeLogs.warning("Unable to load userClicks for poll with id: " + poll); + return null; + } + String sql = "SELECT * FROM poll_buttons WHERE poll_id = ?"; + try { + PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); + statement.setLong(1, poll.getPollId()); + List buttons = new ArrayList<>(); + ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + long internalButtonId = resultSet.getLong("id"); + PollButton pollButton = new PollButton(internalButtonId, resultSet.getString("button_id"), resultSet.getString("button_name"), userClicks.getOrDefault(internalButtonId, new HashSet<>())); + buttonManager.addButton(pollButton); + buttons.add(pollButton); + } + poll.addButtons(buttons); + return buttons; + } catch (SQLException exception) { + exception.printStackTrace(); + } + return null; + } + +} diff --git a/src/main/java/com/alttd/database/queries/Poll/PollQueries.java b/src/main/java/com/alttd/database/queries/Poll/PollQueries.java new file mode 100644 index 0000000..5351a14 --- /dev/null +++ b/src/main/java/com/alttd/database/queries/Poll/PollQueries.java @@ -0,0 +1,72 @@ +package com.alttd.database.queries.Poll; + +import com.alttd.buttonManager.ButtonManager; +import com.alttd.database.Database; +import com.alttd.util.Logger; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class PollQueries { + + public static boolean addPoll(long pollId, long channelId, long guildId, String title) { + new Poll(pollId, channelId, guildId, false, title); + String sql = "INSERT INTO polls (poll_id, channel_id, guild_id, active, poll_title, embed_type) VALUES (?, ?, ?, ?, ?, ?)"; + try { + PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); + statement.setLong(1, pollId); + statement.setLong(2, channelId); + statement.setLong(3, guildId); + statement.setInt(4, 0); + statement.setString(5, title); + statement.setString(6, "POLL_EMBED"); + + return statement.execute(); + } catch (SQLException exception) { + exception.printStackTrace(); + } + return false; + } + + public static boolean setPollStatus(long pollId, boolean active, ButtonManager buttonManager) { + String sql = "UPDATE polls SET active = ? WHERE poll_id = ?"; + try { + Poll poll = Poll.getPoll(pollId); + if (poll == null) { + Logger.altitudeLogs.warning("Received null poll in setPollStatus (query)"); + return false; + } + PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); + statement.setInt(1, active ? 1 : 0); + statement.setLong(2, pollId); + poll.setActive(true); + PollButtonQueries.loadButtons(poll, buttonManager); + return statement.executeUpdate() == 1; + } catch (SQLException exception) { + exception.printStackTrace(); + } + return false; + } + + public static void loadPolls(ButtonManager buttonManager) { + String sql = "SELECT * FROM polls"; + try { + PreparedStatement statement = Database.getDatabase().getConnection().prepareStatement(sql); + + ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + Poll poll = new Poll( + resultSet.getLong("poll_id"), + resultSet.getLong("channel_id"), + resultSet.getLong("guild_id"), + resultSet.getInt("active") == 1, + resultSet.getString("poll_title")); + PollButtonQueries.loadButtons(poll, buttonManager); + Logger.altitudeLogs.debug("Loaded poll: " + poll.getTitle()); + } + } catch (SQLException exception) { + exception.printStackTrace(); + } + } +} diff --git a/src/main/java/com/alttd/listeners/JDAListener.java b/src/main/java/com/alttd/listeners/JDAListener.java index c742e38..b5ff89c 100644 --- a/src/main/java/com/alttd/listeners/JDAListener.java +++ b/src/main/java/com/alttd/listeners/JDAListener.java @@ -3,8 +3,10 @@ package com.alttd.listeners; import com.alttd.buttonManager.ButtonManager; import com.alttd.commandManager.CommandManager; import com.alttd.contextMenuManager.ContextMenuManager; +import com.alttd.database.queries.Poll.PollQueries; import com.alttd.modalManager.ModalManager; import com.alttd.schedulers.AuctionScheduler; +import com.alttd.schedulers.PollTimerTask; import com.alttd.schedulers.ReminderScheduler; import com.alttd.request.RequestManager; import com.alttd.selectMenuManager.SelectMenuManager; @@ -17,6 +19,9 @@ import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEve import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; +import java.util.Timer; +import java.util.concurrent.TimeUnit; + public class JDAListener extends ListenerAdapter { private final JDA jda; @@ -34,8 +39,10 @@ public class JDAListener extends ListenerAdapter { ModalManager modalManager = new ModalManager(buttonManager); ContextMenuManager contextMenuManager = new ContextMenuManager(modalManager); SelectMenuManager selectMenuManager = new SelectMenuManager(); - CommandManager commandManager = new CommandManager(jda, modalManager, contextMenuManager, lockedChannel, selectMenuManager); + CommandManager commandManager = new CommandManager(jda, modalManager, contextMenuManager, lockedChannel, selectMenuManager, buttonManager); jda.addEventListener(buttonManager, modalManager, commandManager, contextMenuManager, lockedChannel, appealRepost, selectMenuManager); + PollQueries.loadPolls(buttonManager); + new Timer().scheduleAtFixedRate(new PollTimerTask(jda, Logger.altitudeLogs), TimeUnit.MINUTES.toMillis(1), TimeUnit.MINUTES.toMillis(5)); startSchedulers(); // RequestManager.init(); } diff --git a/src/main/java/com/alttd/schedulers/PollTimerTask.java b/src/main/java/com/alttd/schedulers/PollTimerTask.java new file mode 100644 index 0000000..67540d7 --- /dev/null +++ b/src/main/java/com/alttd/schedulers/PollTimerTask.java @@ -0,0 +1,69 @@ +package com.alttd.schedulers; + +import com.alttd.AltitudeLogs; +import com.alttd.database.queries.Poll.Poll; +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.TimerTask; + +public class PollTimerTask extends TimerTask { + + private final JDA jda; + private final AltitudeLogs logger; + + public PollTimerTask(JDA jda, AltitudeLogs logger) { + this.jda = jda; + this.logger = logger; + } + + @Override + public void run() { + Collection polls = Poll.getAllPolls(); + for (Poll poll : polls) { + if (poll.needsUpdate()) { + updatePoll(poll); + } + } + } + + private void updatePoll(Poll poll) { + Guild guild = jda.getGuildById(poll.getGuildId()); + if (guild == null) { + logger.warning("Unable to retrieve guild for poll: " + poll.getPollId()); + return; + } + + TextChannel textChannel = guild.getTextChannelById(poll.getChannelId()); + if (textChannel == null) { + logger.warning("Unable to retrieve text channel for poll: " + poll.getPollId()); + return; + } + + textChannel.retrieveMessageById(poll.getPollId()).queue(message -> updatePoll(message, poll)); + } + + private void updatePoll(Message message, Poll poll) { + List embeds = new ArrayList<>(message.getEmbeds()); + if (embeds.isEmpty()) { + logger.warning("Unable to retrieve embeds for poll " + poll.getPollId()); + return; + } + + MessageEmbed messageEmbed = embeds.get(0); + EmbedBuilder embedBuilder = new EmbedBuilder(messageEmbed); + + embedBuilder.setFooter("Counted " + poll.getTotalVotes() + " total votes!"); + embeds.set(0, embedBuilder.build()); + + message.editMessageEmbeds(embeds).queue(); + poll.setUpdated(); + } +}