Added button manager and some buttons for suggestions

Added a way to reload commands
Added a way to set output channels
This commit is contained in:
Teriuihi 2022-09-15 21:34:27 +02:00
parent 49a5903da0
commit 3c9b49ab46
20 changed files with 512 additions and 46 deletions

View File

@ -0,0 +1,38 @@
package com.alttd.buttonManager;
import com.alttd.buttonManager.buttons.suggestionReview.ButtonSuggestionReviewAccept;
import com.alttd.buttonManager.buttons.suggestionReview.ButtonSuggestionReviewDeny;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Optional;
public class ButtonManager extends ListenerAdapter {
private final List<DiscordButton> buttons;
public ButtonManager() {
buttons = List.of(
new ButtonSuggestionReviewAccept(),
new ButtonSuggestionReviewDeny());
}
@Override
public void onButtonInteraction(@NotNull ButtonInteractionEvent event) {
}
public @Nullable Button getButtonFor(String buttonId) {
Optional<DiscordButton> first = buttons.stream()
.filter(discordButton -> discordButton.getButtonId().equalsIgnoreCase(buttonId))
.findFirst();
if (first.isEmpty())
return null;
return first.get().getButton();
}
}

View File

@ -0,0 +1,13 @@
package com.alttd.buttonManager;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
public abstract class DiscordButton {
public abstract String getButtonId();
public abstract void execute(ButtonInteractionEvent event);
public abstract Button getButton();
}

View File

@ -0,0 +1,87 @@
package com.alttd.buttonManager.buttons.suggestionReview;
import com.alttd.buttonManager.DiscordButton;
import com.alttd.database.queries.commandOutputChannels.CommandOutputChannels;
import com.alttd.database.queries.commandOutputChannels.OutputType;
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.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.RestAction;
import java.awt.*;
import java.util.List;
public class ButtonSuggestionReviewAccept extends DiscordButton {
@Override
public String getButtonId() {
return "suggestion_review_accept";
}
@Override
public void execute(ButtonInteractionEvent event) {
Message message = event.getMessage();
long suggestionChannelId = CommandOutputChannels.getOutputChannel(message.getGuild().getIdLong(), OutputType.SUGGESTION);
long modLogChannelId = CommandOutputChannels.getOutputChannel(message.getGuild().getIdLong(), OutputType.MOD_LOG);
List<MessageEmbed> embeds = message.getEmbeds();
if (embeds.size() != 1) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This message contains no embeds, can't be a suggestion"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
Guild guild = event.getGuild();
if (guild == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to retrieve guild"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
GuildMessageChannel suggestionChannel = guild.getChannelById(GuildMessageChannel.class, suggestionChannelId);
if (suggestionChannel == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This server does not have a valid suggestion channel"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
GuildMessageChannel modLogChannel = guild.getChannelById(GuildMessageChannel.class, modLogChannelId);
if (modLogChannel == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This server does not have a valid suggestion channel"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
MessageEmbed reviewMessage = embeds.get(0);
List<MessageEmbed.Field> fields = reviewMessage.getFields();
if (fields.size() != 1) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This message's embed does not contain a field, can't be a suggestion"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
MessageEmbed suggestionMessage = new EmbedBuilder(reviewMessage)
.clearFields()
.setColor(Color.GRAY)
.setTitle(fields.get(0).getName())
.setDescription(fields.get(0).getValue())
.build();
suggestionChannel.sendMessageEmbeds(suggestionMessage).queue(success -> {
message.delete().queue(RestAction.getDefaultSuccess(), Util::handleFailure);
event.replyEmbeds(Util.genericSuccessEmbed("Success", "The suggestion was accepted and posted in the suggestion channel")).setEphemeral(true).queue();
modLogChannel.sendMessageEmbeds(new EmbedBuilder(suggestionMessage).addField("Accepted", event.getUser().getAsMention(), false).setColor(Color.GREEN).build())
.queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}, failure -> event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to send suggestion to the suggestion channel"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure));
}
@Override
public Button getButton() {
return Button.primary(getButtonId(), "Accept Suggestion");
}
}

View File

@ -0,0 +1,73 @@
package com.alttd.buttonManager.buttons.suggestionReview;
import com.alttd.buttonManager.DiscordButton;
import com.alttd.database.queries.commandOutputChannels.CommandOutputChannels;
import com.alttd.database.queries.commandOutputChannels.OutputType;
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.component.ButtonInteractionEvent;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import java.awt.*;
import java.util.List;
public class ButtonSuggestionReviewDeny extends DiscordButton {
@Override
public String getButtonId() {
return "suggestion_review_deny";
}
@Override
public void execute(ButtonInteractionEvent event) {
Message message = event.getMessage();
long channelId = CommandOutputChannels.getOutputChannel(message.getGuild().getIdLong(), OutputType.MOD_LOG);
List<MessageEmbed> embeds = message.getEmbeds();
if (embeds.size() != 1) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This message contains no embeds, can't be a suggestion")).setEphemeral(true).queue();
return;
}
Guild guild = event.getGuild();
if (guild == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to retrieve guild")).setEphemeral(true).queue();
return;
}
GuildMessageChannel channel = guild.getChannelById(GuildMessageChannel.class, channelId);
if (channel == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This server does not have a valid mod log channel")).setEphemeral(true).queue();
return;
}
MessageEmbed reviewMessage = embeds.get(0);
List<MessageEmbed.Field> fields = reviewMessage.getFields();
if (fields.size() != 1) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This message's embed does not contain a field, can't be a suggestion")).setEphemeral(true).queue();
return;
}
MessageEmbed suggestionMessage = new EmbedBuilder(reviewMessage)
.clearFields()
.setColor(Color.RED)
.setTitle(fields.get(0).getName())
.setDescription(fields.get(0).getValue())
.build();
channel.sendMessageEmbeds(suggestionMessage).queue(success -> {
message.delete().queue();
event.replyEmbeds(Util.genericSuccessEmbed("Success", "The suggestion was denied and logged")).setEphemeral(true).queue();
}, failure -> {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to send suggestion to the suggestion channel")).setEphemeral(true).queue();
});
}
@Override
public Button getButton() {
return Button.primary(getButtonId(), "Deny Suggestion");
}
}

View File

@ -2,7 +2,9 @@ package com.alttd.commandManager;
import com.alttd.commandManager.commands.AddCommand.CommandManage;
import com.alttd.commandManager.commands.CommandHelp;
import com.alttd.commandManager.commands.CommandSetOutputChannel;
import com.alttd.commandManager.commands.CommandSuggestion;
import com.alttd.commandManager.commands.CommandUpdateCommands;
import com.alttd.commandManager.commands.PollCommand.CommandPoll;
import com.alttd.database.Database;
import com.alttd.modalManager.ModalManager;
@ -19,8 +21,10 @@ import java.awt.*;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class CommandManager extends ListenerAdapter {
@ -36,7 +40,9 @@ public class CommandManager extends ListenerAdapter {
new CommandManage(jda, this),
new CommandHelp(jda, this),
new CommandPoll(jda, this),
new CommandSuggestion(jda, modalManager, this));
new CommandSuggestion(jda, modalManager, this),
new CommandSetOutputChannel(),
new CommandUpdateCommands(this));
}
@Override
@ -83,6 +89,8 @@ public class CommandManager extends ListenerAdapter {
public List<DiscordCommand> getCommands(Guild guild) {
return commands.stream().filter(command -> {
List<ScopeInfo> scopeInfoList = commandList.get(command.getName());
if (scopeInfoList == null)
return false;
for (ScopeInfo scopeInfo : scopeInfoList) {
switch (scopeInfo.getScope()) {
case GLOBAL -> {

View File

@ -7,8 +7,10 @@ import com.alttd.commandManager.SubOption;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
@ -29,7 +31,7 @@ public class CommandManage extends DiscordCommand {
new SubcommandData("disable", "Disable a command")
.addOption(OptionType.STRING, "command", "Name of the command to disable", true, true)
);
commandData.setDefaultEnabled(true);
commandData.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR));
Util.registerSubOptions(subOptionsMap,
new SubCommandEnable(commandManager, null, this),
new SubCommandEnable(commandManager, null, this)

View File

@ -0,0 +1,4 @@
package com.alttd.commandManager.commands;
public class CommandEvidence {
}

View File

@ -26,7 +26,7 @@ public class CommandHelp extends DiscordCommand {
private final CommandManager commandManager;
private final CommandData commandData;
public CommandHelp(JDA jda, CommandManager commandManager) {
public CommandHelp(JDA jda, CommandManager commandManager) { //TODO make this work without specifying a command...
this.commandManager = commandManager;
commandData = Commands.slash(getName(), "Show info about all commands or a specific command.")

View File

@ -0,0 +1,112 @@
package com.alttd.commandManager.commands;
import com.alttd.commandManager.DiscordCommand;
import com.alttd.database.queries.commandOutputChannels.CommandOutputChannels;
import com.alttd.database.queries.commandOutputChannels.OutputType;
import com.alttd.util.Util;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.unions.GuildChannelUnion;
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.commands.DefaultMemberPermissions;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
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 java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class CommandSetOutputChannel extends DiscordCommand {
private final CommandData commandData;
public CommandSetOutputChannel() {
commandData = Commands.slash(getName(), "Set up output channels")
.addOption(OptionType.STRING, "type", "The type of output channel", true, true)
.addOption(OptionType.CHANNEL, "channel", "The channel the specified output should go into", true)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR));
}
@Override
public String getName() {
return "setoutputchannel";
}
@Override
public void execute(SlashCommandInteractionEvent event) {
Guild guild = event.getGuild();
if (guild == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This command can only be used within guilds")).setEphemeral(true).queue();
return;
}
OptionMapping option = event.getOption("type");
if (option == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find type parameter.")).setEphemeral(true).queue();
return;
}
String type = option.getAsString().toUpperCase();
OutputType outputType;
try {
outputType = OutputType.valueOf(type);
} catch (IllegalArgumentException exception) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Not a valid output type.")).setEphemeral(true).queue();
return;
}
option = event.getOption("channel");
if (option == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to find channel parameter.")).setEphemeral(true).queue();
return;
}
GuildChannelUnion channel = option.getAsChannel();
switch (channel.getType()) {
case TEXT, NEWS, GUILD_NEWS_THREAD, GUILD_PUBLIC_THREAD, GUILD_PRIVATE_THREAD -> {
boolean success = CommandOutputChannels.setOutputChannel(guild.getIdLong(), outputType, channel.getIdLong());
if (success)
event.replyEmbeds(Util.genericSuccessEmbed("Success", "Set channel " + channel.getAsMention() + " as the output channel for " + outputType.name() + "."))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
else
event.replyEmbeds(Util.genericErrorEmbed("Error", "Unable to store the new channel output in the database"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
default -> event.replyEmbeds(Util.genericErrorEmbed("Error", "The channel type " + channel.getType().name() + " is not a valid output channel type"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
}
@Override
public void suggest(CommandAutoCompleteInteractionEvent event) {
AutoCompleteQuery focusedOption = event.getFocusedOption();
if (!focusedOption.getType().equals(OptionType.STRING) || !focusedOption.getName().equalsIgnoreCase("type"))
event.replyChoices(Collections.emptyList()).queue();
String value = focusedOption.getValue().toLowerCase();
List<String> collect = Arrays.stream(OutputType.values())
.map(Enum::name)
.filter(type -> type.toLowerCase().startsWith(value.toLowerCase()))
.collect(Collectors.toList());
for (int i = collect.size(); i > 25; i--) //Can only have 25 options
collect.remove(i - 1);
event.replyChoiceStrings(collect).queue();
}
@Override
public String getHelpMessage() {
return null;
}
@Override
public CommandData getCommandData() {
return commandData;
}
}

View File

@ -11,6 +11,7 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEve
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.interactions.components.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import java.util.Collections;
@ -41,7 +42,7 @@ public class CommandSuggestion extends DiscordCommand {
"Unable to find suggestion modal, please report this issue to Teri")).queue();
return;
}
event.replyModal(modal).queue();
event.replyModal(modal).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
@Override

View File

@ -0,0 +1,65 @@
package com.alttd.commandManager.commands;
import com.alttd.commandManager.CommandManager;
import com.alttd.commandManager.DiscordCommand;
import com.alttd.util.Util;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
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.stream.Collectors;
public class CommandUpdateCommands extends DiscordCommand {
private final CommandData commandData;
private final CommandManager commandManager;
public CommandUpdateCommands(CommandManager commandManager) {
this.commandManager = commandManager;
this.commandData = Commands.slash(getName(), "Updates all commands for this bot in this guild")
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR));
}
@Override
public String getName() {
return "updatecommands";
}
@Override
public void execute(SlashCommandInteractionEvent event) {
Guild guild = event.getGuild();
if (guild == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This command can only be ran from a guild"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
ReplyCallbackAction replyCallbackAction = event.deferReply(true);
List<CommandData> commandDataList = commandManager.getCommands(guild).stream().map(DiscordCommand::getCommandData).collect(Collectors.toList());
guild.updateCommands().addCommands(commandDataList).queue(success -> replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "Updated the commands in this guild"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure), Util::handleFailure);
}
@Override
public void suggest(CommandAutoCompleteInteractionEvent event) {
event.replyChoices(Collections.emptyList()).queue();
}
@Override
public String getHelpMessage() {
return null;
}
@Override
public CommandData getCommandData() {
return commandData;
}
}

View File

@ -6,6 +6,7 @@ import com.alttd.commandManager.SubOption;
import com.alttd.util.Logger;
import com.alttd.util.Util;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.DefaultMemberPermissions;
@ -53,7 +54,7 @@ public class CommandPoll extends DiscordCommand {
new SubcommandData("results", "Get the results for a poll")
.addOption(OptionType.CHANNEL, "channel", "Channel this poll is in", true)
.addOption(OptionType.STRING, "message_id", "Id of the poll you want the results for", true));
commandData.setDefaultPermissions(DefaultMemberPermissions.ENABLED);
commandData.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR));
Util.registerSubOptions(subOptionsMap,
new SubCommandAdd(null,this),
new SubCommandAddButton(null, this),

View File

@ -70,7 +70,7 @@ public class SubCommandAddButton extends SubCommand {
.queue();
return;
}
event.deferReply().queue(hook ->
event.deferReply(true).queue(hook ->
channel.retrieveMessageById(messageId).queue(
message -> updatePoll(channel, rowId, buttonName, message, hook),
throwable -> failedToGetMessage(throwable, hook)));

View File

@ -37,16 +37,16 @@ public class DatabaseTables {
}
private void createPollsTable() {
String sql = "CREATE TABLE IF NOT EXISTS polls(" +
"poll_id BIGINT NOT NULL, " +
"channel_id BIGINT NOT NULL, " +
"guild_id BIGINT NOT NULL, " +
"active BIT DEFAULT b'0', " +
"poll_title VARCHAR(256) NOT NULL, " +
"embed_type VARCHAR(32) DEFAULT 'ABSTRACT_EMBED', " +
"PRIMARY KEY (poll_id)" +
")";
try {
String sql = "CREATE TABLE IF NOT EXISTS polls(" +
"poll_id BIGINT NOT NULL, " +
"channel_id BIGINT NOT NULL, " +
"guild_id BIGINT NOT NULL, " +
"active BIT DEFAULT b'0', " +
"poll_title VARCHAR(256) NOT NULL, " +
"embed_type VARCHAR(32) DEFAULT 'ABSTRACT_EMBED', " +
"PRIMARY KEY (poll_id)" +
")";
connection.prepareStatement(sql).executeUpdate();
} catch (SQLException e) {
Logger.sql(e);
@ -55,13 +55,28 @@ public class DatabaseTables {
}
private void createCommandsTable() {
String sql = "CREATE TABLE IF NOT EXISTS commands(" +
"command_name VARCHAR(64) NOT NULL, " +
"scope VARCHAR(16) NOT NULL, " +
"location_id BIGINT NOT NULL, " +
"PRIMARY KEY (command_name, scope, location_id)" +
")";
try {
connection.prepareStatement(sql).executeUpdate();
} catch (SQLException e) {
Logger.sql(e);
Logger.severe("Unable to create polls table, shutting down...");
}
}
private void createOutputChannelsTable() {
String sql = "CREATE TABLE IF NOT EXISTS output_channels(" +
"guild BIGINT NOT NULL, " +
"output_type VARCHAR(64) NOT NULL, " +
"channel BIGINT NOT NULL, " +
"PRIMARY KEY (guild, output_type, channel)" +
")";
try {
String sql = "CREATE TABLE IF NOT EXISTS commands(" +
"command_name VARCHAR(64) NOT NULL, " +
"scope VARCHAR(16) NOT NULL, " +
"location_id BIGINT NOT NULL, " +
"PRIMARY KEY (command_name, scope, location_id)" +
")";
connection.prepareStatement(sql).executeUpdate();
} catch (SQLException e) {
Logger.sql(e);

View File

@ -10,7 +10,7 @@ import java.sql.SQLException;
public class CommandOutputChannels {
public static boolean setOutputChannel(long guildId, OutputType outputType, long channelId) {
String sql = "INSERT INTO output_channel (guild, output_type, channel) VALUES (?, ?, ?)";
String sql = "INSERT INTO output_channels (guild, output_type, channel) VALUES (?, ?, ?)";
try {
PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql);
preparedStatement.setLong(1, guildId);
@ -31,7 +31,7 @@ public class CommandOutputChannels {
* @return long channel id or 0 if it errors or can't be found
*/
public static long getOutputChannel(long guildId, OutputType outputType) {
String sql = "SELECT channel FROM output_channel WHERE guild = ? AND output_type = ?";
String sql = "SELECT channel FROM output_channels WHERE guild = ? AND output_type = ?";
try {
PreparedStatement preparedStatement = Database.getDatabase().getConnection().prepareStatement(sql);
preparedStatement.setLong(1, guildId);

View File

@ -2,5 +2,6 @@ package com.alttd.database.queries.commandOutputChannels;
public enum OutputType {
SUGGESTION,
SUGGESTION_REVIEW
SUGGESTION_REVIEW,
MOD_LOG
}

View File

@ -1,5 +1,6 @@
package com.alttd.listeners;
import com.alttd.buttonManager.ButtonManager;
import com.alttd.commandManager.CommandManager;
import com.alttd.modalManager.ModalManager;
import com.alttd.util.Logger;
@ -19,7 +20,7 @@ public class JDAListener extends ListenerAdapter {
@Override
public void onReady(@NotNull ReadyEvent event) {
Logger.info("JDA ready to register commands.");
jda.addEventListener(new CommandManager(jda, new ModalManager()));
jda.addEventListener(new CommandManager(jda, new ModalManager(new ButtonManager())));
}
}

View File

@ -1,10 +1,13 @@
package com.alttd.modalManager;
import com.alttd.buttonManager.ButtonManager;
import com.alttd.modalManager.modals.ModalSuggestion;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.events.interaction.ModalInteractionEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import net.dv8tion.jda.api.interactions.components.Modal;
import net.dv8tion.jda.api.requests.RestAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -16,9 +19,9 @@ public class ModalManager extends ListenerAdapter {
private final List<DiscordModal> modals;
public ModalManager() {
public ModalManager(ButtonManager buttonManager) {
modals = List.of(
new ModalSuggestion());
new ModalSuggestion(buttonManager));
}
@Override
@ -34,7 +37,7 @@ public class ModalManager extends ListenerAdapter {
.setColor(Color.RED)
.build())
.setEphemeral(true)
.queue();
.queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
first.get().execute(event);

View File

@ -1,23 +1,36 @@
package com.alttd.modalManager.modals;
import com.alttd.buttonManager.ButtonManager;
import com.alttd.database.queries.commandOutputChannels.CommandOutputChannels;
import com.alttd.database.queries.commandOutputChannels.OutputType;
import com.alttd.modalManager.DiscordModal;
import com.alttd.util.Util;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
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.ModalInteractionEvent;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.components.Modal;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.interactions.components.text.TextInput;
import net.dv8tion.jda.api.interactions.components.text.TextInputStyle;
import net.dv8tion.jda.api.interactions.modals.ModalMapping;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
import java.util.List;
public class ModalSuggestion extends DiscordModal {
private final ButtonManager buttonManager;
public ModalSuggestion(ButtonManager buttonManager) {
this.buttonManager = buttonManager;
}
@Override
public String getModalId() {
return "suggestion";
@ -27,8 +40,8 @@ public class ModalSuggestion extends DiscordModal {
public void execute(ModalInteractionEvent event) {
List<ModalMapping> modalMappings = event.getValues();
if (modalMappings.size() != 2) {
event.replyEmbeds(Util.genericErrorEmbed("Error",
"Found the wrong number of fields in your form input")).setEphemeral(true).queue();
event.replyEmbeds(Util.genericErrorEmbed("Error", "Found the wrong number of fields in your form input"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
String title = modalMappings.get(0).getAsString();
@ -36,28 +49,53 @@ public class ModalSuggestion extends DiscordModal {
Guild guild = event.getGuild();
if (guild == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Couldn't find this guild")).setEphemeral(true).queue();
event.replyEmbeds(Util.genericErrorEmbed("Error", "Couldn't find this guild"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
GuildMessageChannel channel = guild.getChannelById(GuildMessageChannel.class, CommandOutputChannels.getOutputChannel(guild.getIdLong(), OutputType.SUGGESTION_REVIEW));
if (channel == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error",
"This guild does not have a suggestion review channel or it's not the right channel type")).setEphemeral(true).queue();
event.replyEmbeds(Util.genericErrorEmbed("Error", "This guild does not have a suggestion review channel or it's not the right channel type"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
//TODO add user tag in description
MessageEmbed reviewMessage = new EmbedBuilder().setTitle("New suggestion").appendDescription("USER").addField(title, desc, false).build();
channel.sendMessageEmbeds(reviewMessage).queue(success -> success.addReaction(null /*TODO FIX EMOTE this should be buttons*/).queue(aa -> {
MessageEmbed responseEmbed = new EmbedBuilder().setTitle("Your submitted suggestion").addField(title, desc, false).build();
event.replyEmbeds(responseEmbed).setEphemeral(true).queue();
//TODO this should have something incase it errors
}), failure -> {
event.replyEmbeds(Util.genericErrorEmbed("Error", "Couldn't submit suggestion for review")).setEphemeral(true).queue();
//TODO include their suggestion in this error (you can send more than one embed)
});
Member member = event.getMember();
if (member == null) {
event.replyEmbeds(Util.genericErrorEmbed("Error", "This command should only be executed from a guild"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
MessageEmbed suggestionToPlayer = new EmbedBuilder().setTitle("Your suggestion").addField(title, desc, false).build();
MessageEmbed reviewMessage = new EmbedBuilder()
.setTitle("New suggestion")
.appendDescription(member.getAsMention())
.addField(title, desc, false)
.setAuthor(member.getEffectiveName(), null, member.getAvatarUrl())
.setFooter(member.getIdLong() + "")
.build();
channel.sendMessageEmbeds(reviewMessage).queue(
success -> addButtons(success, event.deferReply(true), suggestionToPlayer),
failure -> event.replyEmbeds(Util.genericErrorEmbed("Error", "Couldn't submit suggestion for review."), suggestionToPlayer)
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure));
}
public void addButtons(Message message, ReplyCallbackAction replyCallbackAction, MessageEmbed suggestionToPlayer) {
Button suggestionReviewAccept = buttonManager.getButtonFor("suggestion_review_accept");
Button suggestionReviewDeny = buttonManager.getButtonFor("suggestion_review_deny");
if (suggestionReviewAccept == null || suggestionReviewDeny == null) {
replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "Unable to prepare your suggestion for review."))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
return;
}
message.editMessageComponents().setActionRow(suggestionReviewAccept, suggestionReviewDeny).queue(
success -> replyCallbackAction.setEmbeds(Util.genericSuccessEmbed("Success", "Your suggestion was submitted for review!"), suggestionToPlayer)
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure),
failure -> replyCallbackAction.setEmbeds(Util.genericErrorEmbed("Error", "Couldn't prepare your suggestion for review."), suggestionToPlayer)
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure));
}
@Override
@ -69,7 +107,7 @@ public class ModalSuggestion extends DiscordModal {
.build();
TextInput body = TextInput.create("body", "Body", TextInputStyle.PARAGRAPH)
.setPlaceholder("Your concerns go here")
.setPlaceholder("Suggestion...")
.setRequiredRange(30, 1024)
.setRequired(true)
.build();

View File

@ -33,8 +33,12 @@ public class Util {
.collect(Collectors.toList());
}
public static void ignoreSuccess(Object o) {
// IDK I thought this looked nicer in the .queue call
}
public static void handleFailure(Throwable failure) {
Logger.warning(failure.getMessage());
Logger.severe(failure.getMessage());
}
public static MessageEmbed guildOnlyCommand(String commandName) {