Add support for sending to forums

This commit is contained in:
Vankka 2024-06-20 23:03:58 +03:00
parent f5b8829de1
commit f0427d4890
No known key found for this signature in database
GPG Key ID: 62E48025ED4E7EBB
7 changed files with 57 additions and 13 deletions

View File

@ -1,7 +1,12 @@
package com.discordsrv.api.discord.entity.channel;
import com.discordsrv.api.discord.entity.JDAEntity;
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel;
import java.util.concurrent.CompletableFuture;
public interface DiscordForumChannel extends DiscordChannel, DiscordThreadContainer, JDAEntity<ForumChannel> {
CompletableFuture<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message);
}

View File

@ -26,7 +26,10 @@ public class ThreadConfig {
@Comment("Specify the text or forum channel id and the name of the thread (the thread will be automatically created if it doesn't exist)")
public Long channelId = 0L;
public String threadName = "Minecraft Server chat bridge";
@Comment("Does not effect forums")
public boolean privateThread = false;
}

View File

@ -28,6 +28,7 @@ import com.discordsrv.api.discord.entity.guild.DiscordGuild;
import com.discordsrv.api.discord.entity.guild.DiscordRole;
import com.discordsrv.api.discord.entity.interaction.command.CommandType;
import com.discordsrv.api.discord.entity.interaction.command.DiscordCommand;
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
import com.discordsrv.api.discord.exception.NotReadyException;
import com.discordsrv.api.discord.exception.RestErrorResponseException;
import com.discordsrv.common.DiscordSRV;
@ -49,7 +50,9 @@ import com.github.benmanes.caffeine.cache.Expiry;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.channel.Channel;
import net.dv8tion.jda.api.entities.channel.attribute.IWebhookContainer;
import net.dv8tion.jda.api.entities.channel.concrete.*;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.exceptions.ErrorResponseException;
@ -168,7 +171,7 @@ public class DiscordAPIImpl implements DiscordAPI {
"Failed to deliver message to thread \""
+ threadConfig.threadName + "\" in channel " + container
).accept(t);
throw new RuntimeException(); // Just here to fail the future
throw new RuntimeException("Failed to deliver message to one or more threads");
}
if (threadChannel != null) {
@ -248,7 +251,7 @@ public class DiscordAPIImpl implements DiscordAPI {
private void unarchiveOrCreateThread(
ThreadConfig config,
DiscordThreadContainer container,
DiscordThreadChannel thread,
@Nullable DiscordThreadChannel thread,
CompletableFuture<DiscordThreadChannel> future
) {
if (thread != null) {
@ -268,7 +271,16 @@ public class DiscordAPIImpl implements DiscordAPI {
return;
}
container.createThread(config.threadName, config.privateThread).whenComplete(((threadChannel, t) -> {
CompletableFuture<DiscordThreadChannel> createFuture;
if (container instanceof DiscordForumChannel) {
createFuture = ((DiscordForumChannel) container).createPost(
config.threadName,
SendableDiscordMessage.builder().setContent("\u200B").build() // zero-width-space
);
} else {
createFuture = container.createThread(config.threadName, config.privateThread);
}
createFuture.whenComplete(((threadChannel, t) -> {
if (t != null) {
future.completeExceptionally(t);
} else {
@ -538,12 +550,13 @@ public class DiscordAPIImpl implements DiscordAPI {
return notReady();
}
TextChannel textChannel = jda.getTextChannelById(channelId);
if (textChannel == null) {
GuildChannel channel = jda.getGuildChannelById(channelId);
IWebhookContainer webhookContainer = channel instanceof IWebhookContainer ? (IWebhookContainer) channel : null;
if (webhookContainer == null) {
return CompletableFutureUtil.failed(new IllegalArgumentException("Channel could not be found"));
}
return textChannel.retrieveWebhooks().submit().thenApply(webhooks -> {
return webhookContainer.retrieveWebhooks().submit().thenApply(webhooks -> {
Webhook hook = null;
for (Webhook webhook : webhooks) {
User user = webhook.getOwnerAsUser();
@ -563,7 +576,7 @@ public class DiscordAPIImpl implements DiscordAPI {
return CompletableFuture.completedFuture(webhook);
}
return textChannel.createWebhook("DSRV").submit();
return webhookContainer.createWebhook("DSRV").submit();
}).thenApply(webhook ->
WebhookClient.createClient(
webhook.getJDA(),

View File

@ -4,10 +4,14 @@ import com.discordsrv.api.discord.entity.channel.DiscordChannelType;
import com.discordsrv.api.discord.entity.channel.DiscordForumChannel;
import com.discordsrv.api.discord.entity.channel.DiscordThreadChannel;
import com.discordsrv.api.discord.entity.guild.DiscordGuild;
import com.discordsrv.api.discord.entity.message.SendableDiscordMessage;
import com.discordsrv.common.DiscordSRV;
import com.discordsrv.common.discord.api.entity.message.util.SendableDiscordMessageUtil;
import net.dv8tion.jda.api.entities.channel.attribute.IThreadContainer;
import net.dv8tion.jda.api.entities.channel.concrete.ForumChannel;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.entities.channel.forums.ForumPost;
import net.dv8tion.jda.api.requests.restaction.AbstractThreadCreateAction;
import net.dv8tion.jda.api.requests.restaction.ThreadChannelAction;
import net.dv8tion.jda.api.requests.restaction.pagination.ThreadChannelPaginationAction;
import org.jetbrains.annotations.NotNull;
@ -95,20 +99,31 @@ public class DiscordForumChannelImpl implements DiscordForumChannel {
@Override
public CompletableFuture<DiscordThreadChannel> createThread(String name, boolean privateThread) {
return thread(channel -> channel.createThreadChannel(name, privateThread));
throw new IllegalStateException("Cannot create Threads in Forums without a message");
}
@Override
public CompletableFuture<DiscordThreadChannel> createThread(String name, long messageId) {
return thread(channel -> channel.createThreadChannel(name, messageId));
return thread(channel -> channel.createThreadChannel(name, messageId), result -> result);
}
@Override
public CompletableFuture<DiscordThreadChannel> createPost(String name, SendableDiscordMessage message) {
return thread(
channel -> channel.createForumPost(name, SendableDiscordMessageUtil.toJDASend(message)),
ForumPost::getThreadChannel
);
}
@SuppressWarnings("CodeBlock2Expr")
private CompletableFuture<DiscordThreadChannel> thread(Function<ForumChannel, ThreadChannelAction> action) {
private <R> CompletableFuture<DiscordThreadChannel> thread(
Function<ForumChannel, AbstractThreadCreateAction<R, ?>> action,
Function<R, ThreadChannel> resultMapper
) {
return discordSRV.discordAPI().mapExceptions(() -> {
return action.apply(channel)
.submit()
.thenApply(channel -> discordSRV.discordAPI().getThreadChannel(channel));
.thenApply(result -> discordSRV.discordAPI().getThreadChannel(resultMapper.apply(result)));
});
}

View File

@ -9,6 +9,7 @@ public class FullBootExtension implements BeforeAllCallback, ExtensionContext.St
public static String BOT_TOKEN = System.getenv("DISCORDSRV_AUTOTEST_BOT_TOKEN");
public static String TEST_CHANNEL_ID = System.getenv("DISCORDSRV_AUTOTEST_CHANNEL_ID");
public static String FORUM_CHANNEL_ID = System.getenv("DISCORDSRV_AUTOTEST_FORUM_ID");
public boolean started = false;
@ -16,6 +17,7 @@ public class FullBootExtension implements BeforeAllCallback, ExtensionContext.St
public void beforeAll(ExtensionContext context) {
Assumptions.assumeTrue(BOT_TOKEN != null, "Automated testing bot token");
Assumptions.assumeTrue(TEST_CHANNEL_ID != null, "Automated testing channel id");
Assumptions.assumeTrue(FORUM_CHANNEL_ID != null, "Automated testing forum id");
if (started) return;
started = true;

View File

@ -215,6 +215,7 @@ public class MockDiscordSRV extends AbstractDiscordSRV<IBootstrap, MainConfig, C
DestinationConfig destination = global.destination = new DestinationConfig();
long channelId = Long.parseLong(FullBootExtension.TEST_CHANNEL_ID);
long forumId = Long.parseLong(FullBootExtension.FORUM_CHANNEL_ID);
List<Long> channelIds = destination.channelIds;
channelIds.clear();
@ -222,9 +223,14 @@ public class MockDiscordSRV extends AbstractDiscordSRV<IBootstrap, MainConfig, C
List<ThreadConfig> threadConfigs = destination.threads;
threadConfigs.clear();
ThreadConfig thread = new ThreadConfig();
thread.channelId = channelId;
threadConfigs.add(thread);
ThreadConfig forumThread = new ThreadConfig();
thread.channelId = forumId;
threadConfigs.add(forumThread);
}
return config;
@ -239,7 +245,7 @@ public class MockDiscordSRV extends AbstractDiscordSRV<IBootstrap, MainConfig, C
}
@Override
public void load() throws ConfigException {
public void load() {
messagesConfigLoaded = true;
}
};

View File

@ -146,7 +146,7 @@ public class MinecraftToDiscordChatMessageTest {
}
}
success.complete(text == 1 && thread == 1);
success.complete(text == 1 && thread == 2);
}
}
}