Merge branch 'master' into forms

# Conflicts:
#	src/main/java/com/alttd/AltitudeBot.java
This commit is contained in:
Teriuihi 2024-04-28 17:06:27 +02:00
commit ead56c4585
7 changed files with 219 additions and 4 deletions

View File

@ -28,6 +28,7 @@ public class AltitudeBot {
private static AltitudeBot instance;
private static String path;
public static void main(String[] args) {
if (args.length == 0) { //TODO change scripts so it works with this
System.out.println("Please give the location for the configs as an arg");
@ -49,7 +50,7 @@ public class AltitudeBot {
initConfigs();
jda = JDABuilder.createDefault(SettingsConfig.TOKEN,
GatewayIntent.GUILD_MEMBERS,
GatewayIntent.GUILD_BANS,
GatewayIntent.GUILD_MODERATION,
GatewayIntent.GUILD_EMOJIS_AND_STICKERS,
GatewayIntent.GUILD_WEBHOOKS,
GatewayIntent.GUILD_PRESENCES,
@ -92,7 +93,7 @@ public class AltitudeBot {
return file.getPath();
} catch (URISyntaxException e) {
Logger.altitudeLogs.error("Unable to retrieve config directory");
e.printStackTrace();
Logger.altitudeLogs.error(e);
}
return (null);
}

View File

@ -16,10 +16,12 @@ public class SettingsConfig extends AbstractConfig {
// SETTINGS
public static String TOKEN = "token";
public static String KANBOARD_TOKEN = "kanboard-token";
public static boolean DEBUG = false;
private void loadSettings() {
TOKEN = settingsConfig.getString("settings.token", TOKEN);
KANBOARD_TOKEN = settingsConfig.getString("settings.kanboard-token", KANBOARD_TOKEN);
DEBUG = settingsConfig.getBoolean("settings.debug", DEBUG);
}

View File

@ -1,5 +1,6 @@
package com.alttd.contextMenuManager;
import com.alttd.contextMenuManager.contextMenus.ContextMenuForwardToKanboard;
import com.alttd.contextMenuManager.contextMenus.ContextMenuRespondSuggestion;
import com.alttd.modalManager.ModalManager;
import com.alttd.util.Util;
@ -21,7 +22,8 @@ public class ContextMenuManager extends ListenerAdapter {
public ContextMenuManager(ModalManager modalManager) {
contextMenus = List.of(
new ContextMenuRespondSuggestion(modalManager)
new ContextMenuRespondSuggestion(modalManager),
new ContextMenuForwardToKanboard()
);
}

View File

@ -0,0 +1,52 @@
package com.alttd.contextMenuManager.contextMenus;
import com.alttd.contextMenuManager.DiscordContextMenu;
import com.alttd.util.Kanboard;
import com.alttd.util.Util;
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent;
import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent;
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 java.util.concurrent.CompletableFuture;
public class ContextMenuForwardToKanboard extends DiscordContextMenu {
@Override
public String getContextMenuId() {
return "Forward To Kanboard";
}
@Override
public void execute(UserContextInteractionEvent event) {
event.getInteraction().replyEmbeds(Util.genericErrorEmbed("Error", "This interaction should have been a message interaction"))
.setEphemeral(true).queue(RestAction.getDefaultSuccess(), Util::handleFailure);
}
@Override
public void execute(MessageContextInteractionEvent event) {
if (!event.isFromGuild()) {
return;
}
Message message = event.getInteraction().getTarget();
CompletableFuture<Boolean> booleanCompletableFuture = Kanboard.forwardMessageToKanboard(message);
event.deferReply(true).queue(defer -> booleanCompletableFuture.thenAcceptAsync(result -> {
if (!result) {
defer.editOriginalEmbeds(Util.genericErrorEmbed("Error", "Unable to forward message to Kanboard")).queue();
return;
}
defer.editOriginalEmbeds(Util.genericSuccessEmbed("Success", "Forwarded message to Kanboard board!")).queue();
}));
}
@Override
public CommandData getUserContextInteraction() {
return Commands.message(getContextMenuId())
.setGuildOnly(true)
.setDefaultPermissions(DefaultMemberPermissions.enabledFor(Permission.ADMINISTRATOR));
}
}

View File

@ -40,12 +40,13 @@ public class JDAListener extends ListenerAdapter {
Logger.altitudeLogs.info("JDA ready to register commands.");
LockedChannel lockedChannel = new LockedChannel();
ButtonManager buttonManager = new ButtonManager();
TagAdded tagAdded = new TagAdded();
AppealRepost appealRepost = new AppealRepost(buttonManager);
ModalManager modalManager = new ModalManager(buttonManager);
ContextMenuManager contextMenuManager = new ContextMenuManager(modalManager);
SelectMenuManager selectMenuManager = new SelectMenuManager();
CommandManager commandManager = new CommandManager(jda, modalManager, contextMenuManager, lockedChannel, selectMenuManager, buttonManager);
jda.addEventListener(buttonManager, modalManager, commandManager, contextMenuManager, lockedChannel, appealRepost, selectMenuManager);
jda.addEventListener(buttonManager, tagAdded, 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();

View File

@ -0,0 +1,27 @@
package com.alttd.listeners;
import com.alttd.util.Kanboard;
import com.alttd.util.Logger;
import net.dv8tion.jda.api.entities.ISnowflake;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.entities.channel.forums.ForumTag;
import net.dv8tion.jda.api.events.channel.update.ChannelUpdateAppliedTagsEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import java.util.List;
public class TagAdded extends ListenerAdapter {
@Override
public void onChannelUpdateAppliedTags(ChannelUpdateAppliedTagsEvent event) {
List<ForumTag> addedTags = event.getAddedTags();
if (addedTags.stream().map(ISnowflake::getIdLong).noneMatch(id -> id == 1020378607052398632L)) {//TODO add tag id to config
return;
}
if (!(event.getChannel() instanceof ThreadChannel threadChannel)) {
return;
}
threadChannel.retrieveStartMessage().queue(Kanboard::forwardMessageToKanboard, error -> Logger.altitudeLogs.error(error));
}
}

View File

@ -0,0 +1,130 @@
package com.alttd.util;
import com.alttd.config.SettingsConfig;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class Kanboard {
public static CompletableFuture<Boolean> forwardMessageToKanboard(String title, String body, String webLink) {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request;
String jsonPayload = getPayload(UUID.randomUUID().toString(), title, body, webLink);
try {
byte[] kanboardTokenBytes = String.join(":", "jsonrpc", SettingsConfig.KANBOARD_TOKEN).getBytes(StandardCharsets.UTF_8);
String token = Base64.getEncoder().encodeToString(kanboardTokenBytes);
request = HttpRequest.newBuilder()
.uri(new URI("https://kanboard.alttd.com/jsonrpc.php"))
.header("Content-Type", "application/json")
.setHeader("Authorization", "Basic " + token)
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
.build();
} catch (URISyntaxException e) {
Logger.altitudeLogs.error(e);
//TODO handle better
return CompletableFuture.completedFuture(false);
}
return CompletableFuture.supplyAsync(() -> {
HttpResponse<String> response;
try {
response = client.send(request, HttpResponse.BodyHandlers.ofString());
} catch (InterruptedException | IOException e) {
Logger.altitudeLogs.error(e);
return false;
}
if (response.statusCode() == 200 && response.body().matches(".*\"result\":[0-9]+,.*")) {
Logger.altitudeLogs.info(String.format("Response body: [%s]\nFor JsonPayload: [%s]", response.body(), jsonPayload));
return true;
} else {
Logger.altitudeLogs.error(String.format("Invalid response: [%s]\nPayload: [%s]", response.body(), jsonPayload));
return false;
}
});
}
public static CompletableFuture<Boolean> forwardMessageToKanboard(Message message) {
String body = message.getContentDisplay();
if (messageIsSuggestion(message) && message.getGuildChannel() instanceof ThreadChannel threadChannel) {
return forwardSuggestionToKanboard(message, threadChannel);
}
String[] split = body.split("\n");
String title;
if (split.length == 1) {
title = "No title";
} else {
title = split[0];
body = Arrays.stream(split).skip(1).filter(str -> !str.isBlank()).collect(Collectors.joining("\n"));
}
return forwardMessageToKanboard(title, body, getWebLink(message));
}
private static CompletableFuture<Boolean> forwardSuggestionToKanboard(Message message, ThreadChannel threadChannel) {
String title = threadChannel.getName();
String content = Arrays.stream(message.getContentDisplay().split("\n")).skip(1).filter(str -> !str.isBlank()).collect(Collectors.joining("\n"));
return forwardMessageToKanboard(title, content, getWebLink(message));
}
private static boolean messageIsSuggestion(Message message) {
Member member = message.getMember();
if (member == null)
return false;
if (!member.getUser().equals(message.getJDA().getSelfUser())) {
return false;
}
if (!message.getContentRaw().startsWith("**Suggestion by:")) {
return false;
}
return true;
}
private static String getPayload(String id, String title, String body, String webLink) {
return String.format("""
{
"jsonrpc": "2.0",
"method": "createTask",
"id": "%s",
"params": {
"title": "%s",
"project_id": "3",
"description": "%s%s",
"column_id": "0",
"color_id": "red"
}
}""",
escapeSpecialJsonChars(id),
escapeSpecialJsonChars(title),
escapeSpecialJsonChars(body),
escapeSpecialJsonChars(String.format("\n\n[Discord link](%s)", webLink)));
}
private static String getWebLink(Message message) {
return String.format("https://discord.com/channels/%d/%d/%d", message.getGuildIdLong(), message.getChannelIdLong(), message.getIdLong());
}
private static String escapeSpecialJsonChars(String s) {
return s.replace("\"", "\\\"")
.replace("\\", "\\\\")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
}