Skip to content

Commit 81d1597

Browse files
Merge pull request #346 from danthe1st/qotw-view
2 parents 1338120 + fe11f31 commit 81d1597

File tree

10 files changed

+75
-29
lines changed

10 files changed

+75
-29
lines changed

src/main/java/net/javadiscord/javabot/systems/moderation/PurgeCommand.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import net.javadiscord.javabot.util.TimeUtils;
1515
import org.jetbrains.annotations.NotNull;
1616

17+
import javax.annotation.CheckReturnValue;
1718
import javax.annotation.Nullable;
1819
import java.io.IOException;
1920
import java.io.PrintWriter;
@@ -43,6 +44,7 @@ public PurgeCommand() {
4344
}
4445

4546
@Override
47+
@CheckReturnValue
4648
protected ReplyCallbackAction handleModerationCommand(@NotNull SlashCommandInteractionEvent event, @NotNull Member moderator) {
4749
OptionMapping amountOption = event.getOption("amount");
4850
OptionMapping userOption = event.getOption("user");

src/main/java/net/javadiscord/javabot/systems/qotw/commands/view/QOTWListAnswersSubcommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public void execute(@NotNull SlashCommandInteractionEvent event) {
5151
}
5252
OptionMapping questionNumOption = event.getOption("question");
5353
if (questionNumOption == null) {
54-
Responses.replyMissingArguments(event);
54+
Responses.replyMissingArguments(event).queue();
5555
return;
5656
}
5757
int questionNum = questionNumOption.getAsInt();

src/main/java/net/javadiscord/javabot/systems/qotw/commands/view/QOTWViewAnswerSubcommand.java

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
package net.javadiscord.javabot.systems.qotw.commands.view;
22

3+
import java.util.Comparator;
4+
5+
import org.jetbrains.annotations.NotNull;
6+
37
import com.dynxsty.dih4jda.interactions.commands.SlashCommand;
8+
49
import net.dv8tion.jda.api.EmbedBuilder;
10+
import net.dv8tion.jda.api.entities.ChannelType;
11+
import net.dv8tion.jda.api.entities.Message;
512
import net.dv8tion.jda.api.entities.MessageEmbed;
613
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
714
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
@@ -13,7 +20,6 @@
1320
import net.javadiscord.javabot.systems.qotw.submissions.model.QOTWSubmission;
1421
import net.javadiscord.javabot.util.MessageActionUtils;
1522
import net.javadiscord.javabot.util.Responses;
16-
import org.jetbrains.annotations.NotNull;
1723

1824
/**
1925
* Represents the `/qotw-view answer` subcommand. It allows for viewing an answer to a QOTW.
@@ -38,14 +44,18 @@ public void execute(@NotNull SlashCommandInteractionEvent event) {
3844
}
3945
OptionMapping questionOption = event.getOption("question");
4046
if (questionOption == null) {
41-
Responses.replyMissingArguments(event);
47+
Responses.replyMissingArguments(event).queue();
4248
return;
4349
}
4450
OptionMapping answerOwnerOption = event.getOption("answerer");
4551
if (answerOwnerOption == null) {
4652
Responses.error(event, "The answerer option is missing.").queue();
4753
return;
4854
}
55+
if (event.getChannelType() != ChannelType.TEXT) {
56+
Responses.error(event, "This command can only be used in text channels.").queue();
57+
return;
58+
}
4959
event.deferReply(true).queue();
5060
DbActions.doAsyncDaoAction(QOTWSubmissionRepository::new, repo -> {
5161
QOTWSubmission submission = repo.getSubmissionByQuestionNumberAndAuthorID(event.getGuild().getIdLong(), questionOption.getAsInt(), answerOwnerOption.getAsUser().getIdLong());
@@ -63,8 +73,15 @@ public void execute(@NotNull SlashCommandInteractionEvent event) {
6373
MessageActionUtils.copyMessagesToNewThread(event.getGuildChannel().asStandardGuildMessageChannel(),
6474
buildQOTWInfoEmbed(submission, event.getMember() == null ? event.getUser().getName() : event.getMember().getEffectiveName()),
6575
"QOTW #" + submission.getQuestionNumber(),
66-
history.getRetrievedHistory(),
67-
() -> Responses.success(event.getHook(), "View Answer", "Answer copied successfully"))),
76+
history.getRetrievedHistory()
77+
.stream()
78+
.filter(msg -> !msg.getAuthor().isSystem() && !msg.getAuthor().isBot())
79+
.sorted(Comparator.comparingLong(Message::getIdLong))
80+
.toList(),
81+
thread -> {
82+
Responses.success(event.getHook(), "View Answer", "Answer copied successfully").queue();
83+
thread.getManager().setLocked(true).queue();
84+
})),
6885
() -> Responses.error(event.getHook(), "The QOTW-Submission thread was not found.").queue()));
6986
});
7087
}

src/main/java/net/javadiscord/javabot/systems/qotw/dao/QuestionQueueRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ public List<QOTWQuestion> getQuestions(long guildId, int page, int size) throws
132132
* @throws SQLException If an error occurs.
133133
*/
134134
public List<QOTWQuestion> getUsedQuestionsWithQuery(long guildId, String query, int page, int size) throws SQLException {
135-
String sql = "SELECT * FROM qotw_question WHERE guild_id = ? AND \"text\" LIKE ? AND used = TRUE ORDER BY question_number DESC, created_at ASC LIMIT ? OFFSET ?";
135+
String sql = "SELECT * FROM qotw_question WHERE guild_id = ? AND \"TEXT\" LIKE ? AND used = TRUE ORDER BY question_number DESC, created_at ASC LIMIT ? OFFSET ?";
136136
try (PreparedStatement stmt = con.prepareStatement(sql)) {
137137
stmt.setLong(1, guildId);
138138
stmt.setString(2, "%" + query.toLowerCase() + "%");

src/main/java/net/javadiscord/javabot/systems/qotw/submissions/subcommands/MarkBestAnswerSubcommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ private void sendBestAnswer(InteractionHook hook, List<Message> messages, Member
147147
this.buildBestAnswerEmbed(member),
148148
submissionThread.getName(),
149149
messages,
150-
() -> Responses.success(hook, "Best Answer", "Successfully marked %s as the best answer", submissionThread.getAsMention()).queue());
150+
thread -> Responses.success(hook, "Best Answer", "Successfully marked %s as the best answer", submissionThread.getAsMention()).queue());
151151
}
152152

153153
/**

src/main/java/net/javadiscord/javabot/systems/user_commands/RegexCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void execute(@NotNull SlashCommandInteractionEvent event) {
3838
try {
3939
pattern = Pattern.compile(patternOption.getAsString());
4040
} catch (PatternSyntaxException e) {
41-
Responses.error(event, "Please provide a valid regex pattern!");
41+
Responses.error(event, "Please provide a valid regex pattern!").queue();
4242
return;
4343
}
4444
String string = stringOption.getAsString();

src/main/java/net/javadiscord/javabot/util/MessageActionUtils.java

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
package net.javadiscord.javabot.util;
22

3-
import net.dv8tion.jda.api.entities.GuildMessageChannel;
4-
import net.dv8tion.jda.api.entities.Message;
5-
import net.dv8tion.jda.api.entities.MessageEmbed;
6-
import net.dv8tion.jda.api.interactions.components.ActionRow;
7-
import net.dv8tion.jda.api.interactions.components.ItemComponent;
8-
import net.dv8tion.jda.api.requests.restaction.MessageAction;
9-
103
import java.util.ArrayList;
11-
import java.util.EnumSet;
124
import java.util.List;
135
import java.util.concurrent.CompletableFuture;
6+
import java.util.function.Consumer;
147

158
import org.jetbrains.annotations.NotNull;
169

10+
import club.minnced.discord.webhook.receive.ReadonlyMessage;
11+
import net.dv8tion.jda.api.entities.Message;
12+
import net.dv8tion.jda.api.entities.MessageEmbed;
13+
import net.dv8tion.jda.api.entities.StandardGuildMessageChannel;
14+
import net.dv8tion.jda.api.entities.ThreadChannel;
15+
import net.dv8tion.jda.api.interactions.components.ActionRow;
16+
import net.dv8tion.jda.api.interactions.components.ItemComponent;
17+
import net.dv8tion.jda.api.requests.restaction.MessageAction;
18+
1719
/**
1820
* Utility class for message actions.
1921
*/
@@ -83,17 +85,17 @@ public static CompletableFuture<Message> addAttachmentsAndSend(Message message,
8385
* @param messages The messages to copy.
8486
* @param onFinish A callback to execute when copying is done.
8587
*/
86-
public static void copyMessagesToNewThread(GuildMessageChannel targetChannel, @NotNull MessageEmbed infoEmbed, String newThreadName, List<Message> messages, Runnable onFinish) {
88+
public static void copyMessagesToNewThread(StandardGuildMessageChannel targetChannel, @NotNull MessageEmbed infoEmbed, String newThreadName, List<Message> messages, Consumer<ThreadChannel> onFinish) {
8789
targetChannel.sendMessageEmbeds(infoEmbed).queue(
8890
message -> message.createThreadChannel(newThreadName).queue(
8991
thread -> {
90-
messages.forEach(m -> {
91-
String messageContent = m.getContentRaw();
92-
if (messageContent.trim().length() == 0) messageContent = "[attachment]";
93-
MessageActionUtils.addAttachmentsAndSend(m, thread.sendMessage(messageContent)
94-
.allowedMentions(EnumSet.of(Message.MentionType.EMOJI, Message.MentionType.CHANNEL)));
92+
WebhookUtil.ensureWebhookExists(targetChannel, wh->{
93+
CompletableFuture<ReadonlyMessage> future = CompletableFuture.completedFuture(null);
94+
for (Message m : messages) {
95+
future = future.thenCompose(unused -> WebhookUtil.mirrorMessageToWebhook(wh, m, m.getContentRaw(), thread.getIdLong()));
96+
}
9597
});
96-
onFinish.run();
98+
onFinish.accept(thread);
9799
}
98100
));
99101
}

src/main/java/net/javadiscord/javabot/util/Responses.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import net.javadiscord.javabot.Bot;
1515
import org.jetbrains.annotations.NotNull;
1616

17+
import javax.annotation.CheckReturnValue;
1718
import javax.annotation.Nullable;
1819
import java.awt.*;
1920
import java.time.Instant;
@@ -29,84 +30,104 @@ public final class Responses {
2930
private Responses() {
3031
}
3132

33+
@CheckReturnValue
3234
public static @NotNull ReplyCallbackAction success(CommandInteraction event, String title, String message, Object... args) {
3335
return reply(event, title, String.format(message, args), Type.SUCCESS.getColor(), true);
3436
}
3537

38+
@CheckReturnValue
3639
public static @NotNull WebhookMessageAction<Message> success(InteractionHook hook, String title, String message, Object... args) {
3740
return reply(hook, title, String.format(message, args), Type.SUCCESS.getColor(), true);
3841
}
3942

43+
@CheckReturnValue
4044
public static @NotNull ReplyCallbackAction info(CommandInteraction event, String title, String message, Object... args) {
4145
return reply(event, title, String.format(message, args), Type.INFO.getColor(), true);
4246
}
4347

48+
@CheckReturnValue
4449
public static @NotNull WebhookMessageAction<Message> info(InteractionHook hook, String title, String message, Object... args) {
4550
return reply(hook, title, String.format(message, args), Type.INFO.getColor(), true);
4651
}
4752

53+
@CheckReturnValue
4854
public static @NotNull ReplyCallbackAction error(CommandInteraction event, String message, Object... args) {
4955
return reply(event, "An Error Occurred", String.format(message, args), Type.ERROR.getColor(), true);
5056
}
5157

58+
@CheckReturnValue
5259
public static @NotNull WebhookMessageAction<Message> error(InteractionHook hook, String message, Object... args) {
5360
return reply(hook, "An Error Occurred", String.format(message, args), Type.ERROR.getColor(), true);
5461
}
5562

63+
@CheckReturnValue
5664
public static @NotNull ReplyCallbackAction warning(CommandInteraction event, String message, Object... args) {
5765
return warning(event, null, String.format(message, args));
5866
}
5967

68+
@CheckReturnValue
6069
public static @NotNull WebhookMessageAction<Message> warning(InteractionHook hook, String message, Object... args) {
6170
return warning(hook, null, String.format(message, args));
6271
}
6372

73+
@CheckReturnValue
6474
public static @NotNull ReplyCallbackAction warning(CommandInteraction event, String title, String message, Object... args) {
6575
return reply(event, title, String.format(message, args), Type.WARN.getColor(), true);
6676
}
6777

78+
@CheckReturnValue
6879
public static @NotNull WebhookMessageAction<Message> warning(InteractionHook hook, String title, String message, Object... args) {
6980
return reply(hook, title, String.format(message, args), Type.WARN.getColor(), true);
7081
}
7182

83+
@CheckReturnValue
7284
public static @NotNull ReplyCallbackAction replyMissingArguments(CommandInteraction event) {
7385
return error(event, "Missing required arguments.");
7486
}
7587

88+
@CheckReturnValue
7689
public static @NotNull WebhookMessageAction<Message> replyMissingArguments(InteractionHook hook) {
7790
return error(hook, "Missing required arguments.");
7891
}
7992

93+
@CheckReturnValue
8094
public static @NotNull ReplyCallbackAction replyGuildOnly(CommandInteraction event) {
8195
return error(event, "This command may only be used inside servers.");
8296
}
8397

98+
@CheckReturnValue
8499
public static @NotNull WebhookMessageAction<Message> replyGuildOnly(InteractionHook hook) {
85100
return error(hook, "This command may only be used inside servers.");
86101
}
87102

103+
@CheckReturnValue
88104
public static @NotNull ReplyCallbackAction replyInsufficientPermissions(CommandInteraction event, Permission... permissions) {
89105
return error(event, "I am missing one or more permissions in order to execute this action. (%s)",
90106
Arrays.stream(permissions).map(p -> MarkdownUtil.monospace(p.getName())).collect(Collectors.joining(", ")));
91107
}
92108

109+
@CheckReturnValue
93110
public static @NotNull WebhookMessageAction<Message> replyInsufficientPermissions(InteractionHook hook, Permission... permissions) {
94111
return error(hook, "I am missing one or more permissions in order to execute this action. (%s)",
95112
Arrays.stream(permissions).map(p -> MarkdownUtil.monospace(p.getName())).collect(Collectors.joining(", ")));
96113
}
97114

115+
@CheckReturnValue
98116
public static @NotNull ReplyCallbackAction replyMissingMember(CommandInteraction event) {
99117
return error(event, "The provided user **must** be a member of this server. Please try again.");
100118
}
101119

120+
@CheckReturnValue
102121
public static @NotNull ReplyCallbackAction replyCannotInteract(CommandInteraction event, @NotNull IMentionable mentionable) {
103122
return error(event, "I am missing permissions in order to interact with that. (%s)", mentionable.getAsMention());
104123
}
105124

125+
@CheckReturnValue
106126
public static @NotNull ReplyCallbackAction replyStaffOnly(CommandInteraction event, Guild guild) {
107127
return error(event, "This command may only be used by staff members. (%s)", Bot.getConfig().get(guild).getModerationConfig().getStaffRole().getAsMention());
108128
}
109129

130+
@CheckReturnValue
110131
public static @NotNull ReplyCallbackAction replyAdminOnly(CommandInteraction event, Guild guild) {
111132
return error(event, "This command may only be used by admins. (%s)", Bot.getConfig().get(guild).getModerationConfig().getAdminRole().getAsMention());
112133
}
@@ -121,6 +142,7 @@ private Responses() {
121142
* @param ephemeral Whether the message should be ephemeral.
122143
* @return The reply action.
123144
*/
145+
@CheckReturnValue
124146
private static @NotNull ReplyCallbackAction reply(@NotNull CommandInteraction event, @Nullable String title, String message, Color color, boolean ephemeral) {
125147
return event.replyEmbeds(buildEmbed(title, message, color)).setEphemeral(ephemeral);
126148
}
@@ -135,10 +157,12 @@ private Responses() {
135157
* @param ephemeral Whether the message should be ephemeral.
136158
* @return The webhook message action.
137159
*/
160+
@CheckReturnValue
138161
private static @NotNull WebhookMessageAction<Message> reply(@NotNull InteractionHook hook, @Nullable String title, String message, Color color, boolean ephemeral) {
139162
return hook.sendMessageEmbeds(buildEmbed(title, message, color)).setEphemeral(ephemeral);
140163
}
141164

165+
@CheckReturnValue
142166
private static @NotNull MessageEmbed buildEmbed(@Nullable String title, String message, Color color) {
143167
EmbedBuilder embedBuilder = new EmbedBuilder()
144168
.setTimestamp(Instant.now())

src/main/java/net/javadiscord/javabot/util/WebhookUtil.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
import club.minnced.discord.webhook.WebhookClientBuilder;
44
import club.minnced.discord.webhook.external.JDAWebhookClient;
5+
import club.minnced.discord.webhook.receive.ReadonlyMessage;
56
import club.minnced.discord.webhook.send.AllowedMentions;
67
import club.minnced.discord.webhook.send.WebhookMessageBuilder;
78
import club.minnced.discord.webhook.send.component.LayoutComponent;
89
import net.dv8tion.jda.api.entities.Message;
910
import net.dv8tion.jda.api.entities.Message.Attachment;
10-
import net.dv8tion.jda.api.entities.TextChannel;
11+
import net.dv8tion.jda.api.entities.StandardGuildMessageChannel;
1112
import net.dv8tion.jda.api.entities.Webhook;
1213
import org.jetbrains.annotations.NotNull;
1314

@@ -31,7 +32,7 @@ private WebhookUtil() {
3132
* @param callback an action that is executed once a webhook is
3233
* found/created
3334
*/
34-
public static void ensureWebhookExists(TextChannel channel, Consumer<? super Webhook> callback) {
35+
public static void ensureWebhookExists(StandardGuildMessageChannel channel, Consumer<? super Webhook> callback) {
3536
ensureWebhookExists(channel, callback, err -> {
3637
});
3738
}
@@ -46,7 +47,7 @@ public static void ensureWebhookExists(TextChannel channel, Consumer<? super Web
4647
* @param failureCallback an action that is executed if the webhook
4748
* lookup/creation failed
4849
*/
49-
public static void ensureWebhookExists(@NotNull TextChannel channel, Consumer<? super Webhook> callback, Consumer<? super Throwable> failureCallback) {
50+
public static void ensureWebhookExists(@NotNull StandardGuildMessageChannel channel, Consumer<? super Webhook> callback, Consumer<? super Throwable> failureCallback) {
5051

5152
channel.retrieveWebhooks().queue(webhooks -> {
5253
Optional<Webhook> hook = webhooks.stream()
@@ -72,7 +73,7 @@ public static void ensureWebhookExists(@NotNull TextChannel channel, Consumer<?
7273
* @return a {@link CompletableFuture} representing the action of sending
7374
* the message
7475
*/
75-
public static CompletableFuture<Void> mirrorMessageToWebhook(@NotNull Webhook webhook, @NotNull Message originalMessage, String newMessageContent, long threadId, LayoutComponent @NotNull ... components) {
76+
public static CompletableFuture<ReadonlyMessage> mirrorMessageToWebhook(@NotNull Webhook webhook, @NotNull Message originalMessage, String newMessageContent, long threadId, LayoutComponent @NotNull ... components) {
7677
JDAWebhookClient client = new WebhookClientBuilder(webhook.getIdLong(), webhook.getToken())
7778
.setThreadId(threadId).buildJDA();
7879
WebhookMessageBuilder message = new WebhookMessageBuilder().setContent(newMessageContent)
@@ -90,7 +91,7 @@ public static CompletableFuture<Void> mirrorMessageToWebhook(@NotNull Webhook we
9091
futures[i] = attachment.getProxy().download().thenAccept(
9192
is -> message.addFile((attachment.isSpoiler() ? "SPOILER_" : "") + attachment.getFileName(), is));
9293
}
93-
return CompletableFuture.allOf(futures).thenAccept(unused -> client.send(message.build()))
94+
return CompletableFuture.allOf(futures).thenCompose(unused -> client.send(message.build()))
9495
.whenComplete((result, err) -> client.close());
9596
}
9697
}

src/main/resources/database/schema.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ CREATE TABLE qotw_question
4141
created_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0),
4242
guild_id BIGINT NOT NULL,
4343
created_by BIGINT NOT NULL,
44-
"text" VARCHAR(1024) NOT NULL,
44+
"TEXT" VARCHAR(1024) NOT NULL,
4545
used BOOLEAN NOT NULL DEFAULT FALSE,
4646
question_number INTEGER NULL DEFAULT NULL,
4747
priority INTEGER NOT NULL DEFAULT 0

0 commit comments

Comments
 (0)