Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slash commands for moderation #306

Merged
merged 17 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 37 additions & 17 deletions bot/src/main/java/me/duncte123/skybot/CommandManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import me.duncte123.skybot.commands.utils.EnlargeCommand;
import me.duncte123.skybot.commands.utils.RoleInfoCommand;
import me.duncte123.skybot.commands.weeb.*;
import me.duncte123.skybot.entities.jda.DunctebotGuild;
import me.duncte123.skybot.objects.SlashSupport;
import me.duncte123.skybot.objects.command.*;
import me.duncte123.skybot.objects.pairs.LongLongPair;
Expand Down Expand Up @@ -745,29 +746,48 @@ public List<SlashCommandData> getAllSlashCommands() {
}

public void executeSlashCommand(SlashCommandInteractionEvent event) {
final String fullCommandName = event.getFullCommandName();
this.commandThread.submit(() -> {
try {
MDC.put("command.invoke", event.getFullCommandName());
MDC.put("user.tag", event.getUser().getAsTag());
MDC.put("user.name", event.getUser().getEffectiveName());
MDC.put("user.id", event.getUser().getId());
MDC.put("guild", event.isFromGuild() ? event.getGuild().toString() : "(not in guild)");
setJDAContext(event.getJDA());

if (fullCommandName.startsWith("music")) {
final String musicName = fullCommandName.replace("music", "").trim();
final MusicCommand command = (MusicCommand) this.getCommand(musicName);
final var guild = new DunctebotGuild(event.getGuild(), variables);

if (command != null) {
command.handleEvent(event, variables);
}
final String fullCommandName = event.getFullCommandName();

return;
}
if (fullCommandName.startsWith("music")) {
final String musicName = fullCommandName.replace("music", "").trim();
final MusicCommand command = (MusicCommand) this.getCommand(musicName);

try {
final SlashSupport command = (SlashSupport) this.getCommand(event.getName());
if (command != null) {
command.handleEvent(event, guild, variables);
}

return;
}

if (command != null) {
command.executeEventWithChecks(event, variables);
final SlashSupport command = (SlashSupport) this.getCommand(event.getName());

if (command != null) {
command.executeEventWithChecks(event, guild, variables);
}
}
}
catch (Exception e) {
e.printStackTrace();
}
catch (Exception e) {
event.reply(
"Failed to run command: %s\nPlease join [my discord server](https://duncte.bot/discord) if this happens a lot.".formatted(
e.getMessage()
)
).queue();
LOGGER.error(
"Error in '%s'".formatted(event.getCommandString()),
e
);
}
});
}

private static long calcTimeRemaining(long startTime) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,23 @@

import me.duncte123.botcommons.messaging.EmbedUtils;
import me.duncte123.botcommons.messaging.MessageConfig;
import me.duncte123.skybot.extensions.StringKt;
import me.duncte123.skybot.Variables;
import me.duncte123.skybot.entities.jda.DunctebotGuild;
import me.duncte123.skybot.objects.command.CommandCategory;
import me.duncte123.skybot.objects.command.CommandContext;
import me.duncte123.skybot.objects.command.Flag;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel;
import net.dv8tion.jda.api.entities.channel.ChannelType;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nonnull;
import java.util.List;

import static me.duncte123.botcommons.messaging.MessageUtils.*;
import static me.duncte123.botcommons.messaging.MessageUtils.sendMsg;

public class AnnounceCommand extends ModBaseCommand {

Expand All @@ -59,66 +63,110 @@ public AnnounceCommand() {
}

@Override
public void execute(@Nonnull CommandContext ctx) {
final List<GuildMessageChannel> mentioned = ctx.getMessage().getMentions().getChannels(GuildMessageChannel.class);
protected void configureSlashSupport(@NotNull SlashCommandData baseData) {
baseData.addOptions(
new OptionData(
OptionType.CHANNEL,
"channel",
"Channel to send the message to",
true
),
new OptionData(
OptionType.STRING,
"message",
"The message to send",
true
),
new OptionData(
OptionType.ATTACHMENT,
"image",
"An image to send in the embed",
false
),
new OptionData(
OptionType.BOOLEAN,
"embed",
"Use an embed instead of plain text (defaults to true)",
false
),
new OptionData(
OptionType.BOOLEAN,
"thumbnail",
"Set the image as a thumbnail instead of a large image",
false
)
);
}

if (mentioned.isEmpty()) {
sendMsg(ctx, "You did not specify a channel, usage: " + this.getUsageInstructions(ctx));
@Override
public void handleEvent(@NotNull SlashCommandInteractionEvent event, @NotNull DunctebotGuild guild, @NotNull Variables variables) {
final var channel = event.getOption("channel").getAsChannel();

if (channel.getType() != ChannelType.TEXT) {
event.reply("That channel is not a text channel!").queue();
return;
}

final GuildMessageChannel targetChannel = mentioned.get(0);
final var txtChan = channel.asGuildMessageChannel();

if (!targetChannel.canTalk()) {
sendErrorWithMessage(ctx.getMessage(), "I can not talk in " + targetChannel.getAsMention());
if (!txtChan.canTalk()) {
event.reply("I can't talk in that channel").queue();
return;
}

final var flags = ctx.getParsedFlags(this);
final List<String> text = flags.get("undefined");
final var message = event.getOption("message").getAsString();

if (text.isEmpty()) {
this.sendUsageInstructions(ctx);
return;
}
final var useEmbedOption = event.getOption("embed");
final var useEmbed = useEmbedOption == null || useEmbedOption.getAsBoolean();

final String msg = StringKt.stripFlags(
ctx.getArgsRaw()
.replace(targetChannel.getAsMention(), ""),
this
);
if (!useEmbed) {
event.reply("Sending message.....").queue();

if (flags.containsKey("noembed")) {
sendMsg(
new MessageConfig.Builder()
.setChannel(targetChannel)
.setMessage(msg)
.setChannel(txtChan)
.setMessage(message)
.setSuccessAction((msg) -> {
event.getHook()
.editOriginal("Message sent: " + msg.getJumpUrl())
.queue();
})
);
sendSuccess(ctx.getMessage());

return;
}

final EmbedBuilder embed = EmbedUtils.getDefaultEmbed()
.setDescription(message)
.setFooter(null, "");

final EmbedBuilder embed = EmbedUtils.getDefaultEmbed().setDescription(msg).setFooter(null, "");
final List<Message.Attachment> attachments = ctx.getMessage().getAttachments();
final var attachmentOption = event.getOption("image");
final var useThumbOption = event.getOption("thumbnail");

if (!attachments.isEmpty()) {
attachments.stream().filter(Message.Attachment::isImage).findFirst().ifPresent((attachment) -> {
if (flags.containsKey("thumbnail")) {
embed.setThumbnail(attachment.getUrl());
} else {
embed.setImage(attachment.getUrl());
}
});
// TODO: download the attachment??
if (attachmentOption != null) {
if (useThumbOption != null && useThumbOption.getAsBoolean()) {
embed.setThumbnail(attachmentOption.getAsAttachment().getUrl());
} else {
embed.setImage(attachmentOption.getAsAttachment().getUrl());
}
}

event.reply("Sending message.....").queue();

sendMsg(new MessageConfig.Builder()
.setChannel(targetChannel)
.setChannel(txtChan)
.addEmbed(embed)
.setSuccessAction((msg) -> {
event.getHook()
.editOriginal("Message sent: " + msg.getJumpUrl())
.queue();
})
.build());

sendSuccess(ctx.getMessage());
}

@Override
public void execute(@Nonnull CommandContext ctx) {
sendMsg(ctx, "Guess what! Even this is a slash command now!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@

package me.duncte123.skybot.commands.guild.mod;

import me.duncte123.skybot.Variables;
import me.duncte123.skybot.database.AbstractDatabase;
import me.duncte123.skybot.entities.jda.DunctebotGuild;
import me.duncte123.skybot.objects.command.CommandContext;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData;
import net.dv8tion.jda.api.utils.MiscUtil;
import org.jetbrains.annotations.NotNull;

Expand All @@ -33,6 +39,49 @@ public AutoBanBypassCommand() {
this.usage = "<user id>";
}

@Override
protected void configureSlashSupport(@NotNull SlashCommandData baseData) {
baseData.addOptions(
new OptionData(
OptionType.USER,
"user_id",
"The id of the user that you want to create the bypass for.",
true
)
);
}

@Override
public void handleEvent(@NotNull SlashCommandInteractionEvent event, @NotNull DunctebotGuild guild, @NotNull Variables variables) {
final var checkId = event.getOption("user_id").getAsLong();

final var database = variables.getDatabase();
final var guildId = event.getGuild().getIdLong();

event.deferReply().queue();

database.getBanBypass(guildId, checkId).thenAccept((byPass) -> {
if (byPass == null) {
database.createBanBypass(guildId, checkId);
event.getHook()
.editOriginal("Single use bypass created, please note that this bypass will expire after a week if unused." +
"\nPlease keep in mind that this has not unbanned any user, meaning that you will have to unban the user yourself if they are banned")
.queue();
return;
}

event.getHook()
.editOriginal("A bypass already exists for this user")
.queue();
}).exceptionally((thr) -> {
event.getHook()
.editOriginal("Something went wrong: " + thr.getMessage())
.queue();

return null;
});
}

@Override
public void execute(@NotNull CommandContext ctx) {
final long checkId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,23 @@

package me.duncte123.skybot.commands.guild.mod;

import me.duncte123.skybot.Variables;
import me.duncte123.skybot.entities.jda.DunctebotGuild;
import me.duncte123.skybot.objects.command.CommandContext;
import me.duncte123.skybot.objects.command.Flag;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nonnull;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static me.duncte123.botcommons.messaging.MessageUtils.sendMsg;
Expand Down Expand Up @@ -60,6 +69,59 @@ public BanCommand() {
};
}

@Override
protected void configureSlashSupport(@NotNull SlashCommandData baseData) {
baseData.addOptions(
new OptionData(
OptionType.USER,
"user",
"The user that you want to ban.",
true
),
new OptionData(
OptionType.STRING,
"reason",
"The reason for this ban",
false
),
new OptionData(
OptionType.BOOLEAN,
"nodel",
"Prevents the deletion of any messages",
false
)
);
}

@Override
public void handleEvent(@NotNull SlashCommandInteractionEvent event, @NotNull DunctebotGuild guild, @NotNull Variables variables) {
final var toBanMember = event.getOption("user").getAsMember();
final var moderator = event.getMember();

if (!canInteract(moderator, toBanMember, "ban", event.getChannel())) {
return;
}

final var reason = Optional.ofNullable(event.getOption("reason"))
.map(OptionMapping::getAsString)
.orElse("No reason given");
final var nodel = Optional.ofNullable(event.getOption("nodel"))
.map(OptionMapping::getAsBoolean)
.orElse(false);

final int delDays = nodel ? 0 : 1;
final var modUser = moderator.getUser();

guild.ban(toBanMember, delDays, TimeUnit.DAYS)
.reason(String.format("%#s: %s", modUser, reason))
.queue(
(m) -> {
modLog(modUser, toBanMember.getUser(), "banned", reason, null, guild);
event.reply("User has been banned").queue();
}
);
}

@Override
public void execute(@Nonnull CommandContext ctx) {
final List<String> args = ctx.getArgs();
Expand Down
Loading
Loading