From b393ed49427fbf4e5f380a1716834ce7fab78341 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Fri, 12 Aug 2022 09:56:51 +0200 Subject: [PATCH 01/20] initial commit --- .../togetherjava/tjbot/commands/basic/UploadFileToPaste.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/basic/UploadFileToPaste.java diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/basic/UploadFileToPaste.java b/application/src/main/java/org/togetherjava/tjbot/commands/basic/UploadFileToPaste.java new file mode 100644 index 0000000000..d0bbad4fbb --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/basic/UploadFileToPaste.java @@ -0,0 +1,4 @@ +package org.togetherjava.tjbot.commands.basic; + +public class UploadFileToPaste { +} From 5231378d99376cdefd7ace3b095b5b27ea054a94 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Fri, 12 Aug 2022 20:13:11 +0200 Subject: [PATCH 02/20] initial commit --- .../togetherjava/tjbot/commands/Features.java | 7 +- .../tjbot/commands/filesharing/GistFile.java | 14 ++ .../commands/filesharing/GistResponse.java | 18 ++ .../ShareLongAttachmentsMessageListener.java | 174 ++++++++++++++++++ .../commands/filesharing/package-info.java | 5 + 5 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java index 401171192a..d9ab95d566 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java @@ -2,10 +2,8 @@ import net.dv8tion.jda.api.JDA; import org.jetbrains.annotations.NotNull; -import org.togetherjava.tjbot.commands.basic.PingCommand; -import org.togetherjava.tjbot.commands.basic.RoleSelectCommand; -import org.togetherjava.tjbot.commands.basic.SuggestionsUpDownVoter; -import org.togetherjava.tjbot.commands.basic.VcActivityCommand; +import org.togetherjava.tjbot.commands.basic.*; +import org.togetherjava.tjbot.commands.filesharing.ShareLongAttachmentsMessageListener; import org.togetherjava.tjbot.commands.help.*; import org.togetherjava.tjbot.commands.mathcommands.TeXCommand; import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.WolframAlphaCommand; @@ -81,6 +79,7 @@ public enum Features { features.add(new SuggestionsUpDownVoter(config)); features.add(new ScamBlocker(actionsStore, scamHistoryStore, config)); features.add(new ImplicitAskListener(config, helpSystemHelper)); + features.add(new ShareLongAttachmentsMessageListener(config)); // Event receivers features.add(new RejoinModerationRoleListener(actionsStore, config)); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java new file mode 100644 index 0000000000..5fddd0cc0f --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java @@ -0,0 +1,14 @@ +package org.togetherjava.tjbot.commands.filesharing; + +public class GistFile { + + private String content; + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java new file mode 100644 index 0000000000..25aeccf70b --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java @@ -0,0 +1,18 @@ +package org.togetherjava.tjbot.commands.filesharing; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class GistResponse { + @JsonProperty("html_url") + private String htmlUrl; + + public String getHtmlUrl() { + return this.htmlUrl; + } + + public void setHtmlUrl(String htmlUrl) { + this.htmlUrl = htmlUrl; + } +} diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java new file mode 100644 index 0000000000..0c527d0588 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java @@ -0,0 +1,174 @@ +package org.togetherjava.tjbot.commands.filesharing; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.entities.Emoji; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.ThreadChannel; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.togetherjava.tjbot.commands.MessageReceiverAdapter; +import org.togetherjava.tjbot.config.Config; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +public class ShareLongAttachmentsMessageListener extends MessageReceiverAdapter { + + private static final ObjectMapper JSON = new ObjectMapper(); + private static final Logger logger = + LoggerFactory.getLogger(ShareLongAttachmentsMessageListener.class); + + private final Set extensions = Set.of("txt", "java", "gradle", "xml", "kt", "json", + "fxml", "css", "c", "h", "cpp", "py", "yml"); + + private static final String API_KEY = "< placeholder >"; + private static final String API = "https://api.github.com/gists"; + private static final HttpClient CLIENT = HttpClient.newHttpClient(); + + private final Predicate isStagingChannelName; + private final Predicate isOverviewChannelName; + + public ShareLongAttachmentsMessageListener(@NotNull Config config) { + super(Pattern.compile(".*")); + + isStagingChannelName = Pattern.compile(config.getHelpSystem().getStagingChannelPattern()) + .asMatchPredicate(); + isOverviewChannelName = Pattern.compile(config.getHelpSystem().getOverviewChannelPattern()) + .asMatchPredicate(); + } + + @Override + public void onMessageReceived(@NotNull MessageReceivedEvent event) { + if (event.getAuthor().isBot() || event.isWebhookMessage()) { + return; + } + + if (!isHelpThread(event)) { + return; + } + + event.getMessage() + .getAttachments() + .stream() + .filter(attachment -> extensions.contains(attachment.getFileExtension())) + .forEach(attachment -> processAttachment(event, attachment)); + } + + private void processAttachment(MessageReceivedEvent event, Message.Attachment attachment) { + attachment.retrieveInputStream() + .thenApply(this::readAttachment) + .thenApply(content -> uploadToSharingService(event, attachment, content)) + .thenAccept(response -> sendMessage(event, attachment, response)); + } + + private String readAttachment(@NotNull InputStream stream) { + try { + byte[] bytes = stream.readAllBytes(); + return new String(bytes, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private HttpResponse uploadToSharingService(MessageReceivedEvent event, + Message.Attachment attachment, String content) { + GistFile file = new GistFile(); + file.setContent(content); + + String parsedContent; + try { + parsedContent = JSON.writeValueAsString(file); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Couldn't parse content!", e); + } + + String fileName = attachment.getFileName(); + String fileExtension = attachment.getFileExtension(); + + if (fileExtension == null || fileExtension.equals("txt")) { + fileExtension = "java"; + } else if (fileExtension.equals("fxml")) { + fileExtension = "xml"; + } + + fileName = fileName.substring(0, fileName.lastIndexOf(".")) + "." + fileExtension; + + String body = """ + { + "description": "%s", + "public": false, + "files": { + "%s": %s + } + }""".formatted(event.getAuthor(), fileName, parsedContent); + + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(API)) + .header("Accept", "application/json") + .header("Authorization", "token " + API_KEY) + .POST(HttpRequest.BodyPublishers.ofString(body)) + .build(); + + try { + return CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private void sendMessage(MessageReceivedEvent event, Message.Attachment attachment, + HttpResponse response) { + if (response.statusCode() < 200 || response.statusCode() > 299) { + logger.warn("Gist API unexpected response: " + response.body()); + throw new IllegalStateException("Gist API unexpected response: " + response.body()); + } + + Message message = event.getMessage(); + String fileName = attachment.getFileName(); + + GistResponse gistResponse = null; + try { + gistResponse = JSON.readValue(response.body(), GistResponse.class); + } catch (JsonProcessingException e) { + throw new IllegalStateException("Couldn't parse response...", e); + } + + String url = gistResponse.getHtmlUrl(); + + message.reply( + "I uploaded your file as gist, it is much easier to read for everyone like that especially for mobile users!") + .setActionRow(Button.of(ButtonStyle.LINK, url, fileName)) + .queue(); + } + + private boolean isHelpThread(@NotNull MessageReceivedEvent event) { + if (event.getChannelType() != ChannelType.GUILD_PUBLIC_THREAD) { + return false; + } + + ThreadChannel thread = event.getThreadChannel(); + String rootChannelName = thread.getParentChannel().getName(); + return isStagingChannelName.test(rootChannelName) + || isOverviewChannelName.test(rootChannelName); + } + +} diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java new file mode 100644 index 0000000000..d4d304948b --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java @@ -0,0 +1,5 @@ +/** + * This package offers all the functionality for automatically uploading files to gist The core + * class is {@link org.togetherjava.tjbot.commands.filesharing.ShareLongAttachmentsMessageListener} + */ +package org.togetherjava.tjbot.commands.filesharing; From 91a19a41558ca7e5fd50ea523dd9f777daf48ec6 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Fri, 12 Aug 2022 20:13:46 +0200 Subject: [PATCH 03/20] delete --- .../togetherjava/tjbot/commands/basic/UploadFileToPaste.java | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/basic/UploadFileToPaste.java diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/basic/UploadFileToPaste.java b/application/src/main/java/org/togetherjava/tjbot/commands/basic/UploadFileToPaste.java deleted file mode 100644 index d0bbad4fbb..0000000000 --- a/application/src/main/java/org/togetherjava/tjbot/commands/basic/UploadFileToPaste.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.togetherjava.tjbot.commands.basic; - -public class UploadFileToPaste { -} From d7b4b1b8735eb3e68b04644e00e49f1392190156 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sat, 13 Aug 2022 15:58:21 +0200 Subject: [PATCH 04/20] worked on PR comments --- .../tjbot/commands/filesharing/GistFile.java | 18 ++- .../tjbot/commands/filesharing/GistFiles.java | 26 ++++ .../commands/filesharing/GistRequest.java | 31 +++++ .../commands/filesharing/GistResponse.java | 11 +- .../ShareLongAttachmentsMessageListener.java | 118 ++++++++++-------- .../commands/filesharing/package-info.java | 5 +- .../org/togetherjava/tjbot/config/Config.java | 12 ++ 7 files changed, 157 insertions(+), 64 deletions(-) create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java index 5fddd0cc0f..86b5cad272 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java @@ -1,14 +1,20 @@ package org.togetherjava.tjbot.commands.filesharing; -public class GistFile { +import org.jetbrains.annotations.NotNull; - private String content; +/** + * @see Create a Gist via + * API + */ +final class GistFile { - public String getContent() { - return this.content; - } + private @NotNull String content; - public void setContent(String content) { + public GistFile(@NotNull String content) { this.content = content; } + + public @NotNull String getContent() { + return this.content; + } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java new file mode 100644 index 0000000000..292c27edc3 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java @@ -0,0 +1,26 @@ +package org.togetherjava.tjbot.commands.filesharing; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +/** + * @see Create a Gist via + * API + */ +final class GistFiles { + + @JsonIgnore + private Map nameToContent; + + public GistFiles(@NotNull Map nameToContent) { + this.nameToContent = nameToContent; + } + + @JsonAnyGetter + public @NotNull Map getFiles() { + return nameToContent; + } +} diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java new file mode 100644 index 0000000000..73fecf0d84 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java @@ -0,0 +1,31 @@ +package org.togetherjava.tjbot.commands.filesharing; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.jetbrains.annotations.NotNull; + +final class GistRequest { + + private String description; + @JsonProperty("public") + private boolean isPublic; + private GistFiles files; + + public GistRequest(@NotNull String description, @NotNull boolean isPublic, + @NotNull GistFiles files) { + this.description = description; + this.isPublic = isPublic; + this.files = files; + } + + public @NotNull String getDescription() { + return description; + } + + public @NotNull boolean isPublic() { + return isPublic; + } + + public @NotNull GistFiles getFiles() { + return files; + } +} diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java index 25aeccf70b..af7d3f2ddf 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java @@ -2,17 +2,22 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import org.jetbrains.annotations.NotNull; +/** + * @see Create a Gist via + * API + */ @JsonIgnoreProperties(ignoreUnknown = true) -public class GistResponse { +final class GistResponse { @JsonProperty("html_url") private String htmlUrl; - public String getHtmlUrl() { + public @NotNull String getHtmlUrl() { return this.htmlUrl; } - public void setHtmlUrl(String htmlUrl) { + public void setHtmlUrl(@NotNull String htmlUrl) { this.htmlUrl = htmlUrl; } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java index 0c527d0588..69e426f93e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import net.dv8tion.jda.api.entities.ChannelType; -import net.dv8tion.jda.api.entities.Emoji; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.ThreadChannel; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; @@ -18,27 +17,33 @@ import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; +import java.net.HttpURLConnection; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; -import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Predicate; import java.util.regex.Pattern; -public class ShareLongAttachmentsMessageListener extends MessageReceiverAdapter { +/** + * Listener that receives all sent help messages and uploads them to a share service if the message + * contains a file with the given extension in the + * {@link ShareLongAttachmentsMessageListener#extensionFilter} + */ +public final class ShareLongAttachmentsMessageListener extends MessageReceiverAdapter { private static final ObjectMapper JSON = new ObjectMapper(); - private static final Logger logger = + private static final Logger LOGGER = LoggerFactory.getLogger(ShareLongAttachmentsMessageListener.class); - private final Set extensions = Set.of("txt", "java", "gradle", "xml", "kt", "json", + private final Set extensionFilter = Set.of("txt", "java", "gradle", "xml", "kt", "json", "fxml", "css", "c", "h", "cpp", "py", "yml"); - private static final String API_KEY = "< placeholder >"; - private static final String API = "https://api.github.com/gists"; + private final String API_KEY; + private static final String SHARE_API = "https://api.github.com/gists"; private static final HttpClient CLIENT = HttpClient.newHttpClient(); private final Predicate isStagingChannelName; @@ -47,6 +52,7 @@ public class ShareLongAttachmentsMessageListener extends MessageReceiverAdapter public ShareLongAttachmentsMessageListener(@NotNull Config config) { super(Pattern.compile(".*")); + API_KEY = config.getShareApiKey(); isStagingChannelName = Pattern.compile(config.getHelpSystem().getStagingChannelPattern()) .asMatchPredicate(); isOverviewChannelName = Pattern.compile(config.getHelpSystem().getOverviewChannelPattern()) @@ -63,40 +69,33 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { return; } - event.getMessage() - .getAttachments() - .stream() - .filter(attachment -> extensions.contains(attachment.getFileExtension())) - .forEach(attachment -> processAttachment(event, attachment)); + event.getMessage().getAttachments().stream().filter(attachment -> { + String fileExtension = attachment.getFileExtension(); + if (fileExtension == null) { + return false; + } + return extensionFilter.contains(fileExtension); + }).forEach(attachment -> processAttachment(event, attachment)); } - private void processAttachment(MessageReceivedEvent event, Message.Attachment attachment) { + private void processAttachment(@NotNull MessageReceivedEvent event, + @NotNull Message.Attachment attachment) { attachment.retrieveInputStream() .thenApply(this::readAttachment) .thenApply(content -> uploadToSharingService(event, attachment, content)) - .thenAccept(response -> sendMessage(event, attachment, response)); + .thenAccept(url -> sendResponse(event, attachment, url)); } - private String readAttachment(@NotNull InputStream stream) { + private @NotNull String readAttachment(@NotNull InputStream stream) { try { - byte[] bytes = stream.readAllBytes(); - return new String(bytes, StandardCharsets.UTF_8); + return new String(stream.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException e) { throw new UncheckedIOException(e); } } - private HttpResponse uploadToSharingService(MessageReceivedEvent event, - Message.Attachment attachment, String content) { - GistFile file = new GistFile(); - file.setContent(content); - - String parsedContent; - try { - parsedContent = JSON.writeValueAsString(file); - } catch (JsonProcessingException e) { - throw new IllegalStateException("Couldn't parse content!", e); - } + private @NotNull String uploadToSharingService(@NotNull MessageReceivedEvent event, + @NotNull Message.Attachment attachment, @NotNull String content) { String fileName = attachment.getFileName(); String fileExtension = attachment.getFileExtension(); @@ -109,53 +108,66 @@ private HttpResponse uploadToSharingService(MessageReceivedEvent event, fileName = fileName.substring(0, fileName.lastIndexOf(".")) + "." + fileExtension; - String body = """ - { - "description": "%s", - "public": false, - "files": { - "%s": %s - } - }""".formatted(event.getAuthor(), fileName, parsedContent); + GistFiles files = new GistFiles(Map.of(fileName, new GistFile(content))); + GistRequest jsonRequest = new GistRequest(event.getAuthor().getName(), false, files); + String body; + try { + body = JSON.writeValueAsString(jsonRequest); + } catch (JsonProcessingException e) { + LOGGER.warn("Couldn't parse json request!", e); // cause exception doesn't show in + // gradle run: + // https://github.com/Together-Java/TJ-Bot/issues/490 + throw new IllegalStateException("Couldn't parse json request!", e); + } HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(API)) + .uri(URI.create(SHARE_API)) .header("Accept", "application/json") .header("Authorization", "token " + API_KEY) .POST(HttpRequest.BodyPublishers.ofString(body)) .build(); + HttpResponse apiResponse; try { - return CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); + apiResponse = CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); } catch (IOException e) { throw new UncheckedIOException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } - } - private void sendMessage(MessageReceivedEvent event, Message.Attachment attachment, - HttpResponse response) { - if (response.statusCode() < 200 || response.statusCode() > 299) { - logger.warn("Gist API unexpected response: " + response.body()); - throw new IllegalStateException("Gist API unexpected response: " + response.body()); - } + int statusCode = apiResponse.statusCode(); - Message message = event.getMessage(); - String fileName = attachment.getFileName(); + if (statusCode < HttpURLConnection.HTTP_OK + || statusCode >= HttpURLConnection.HTTP_MULT_CHOICE) { + LOGGER.warn("Gist API unexpected response: {}", apiResponse.body()); // cause exception + // doesn't show in + // gradle run: + // https://github.com/Together-Java/TJ-Bot/issues/490 + throw new IllegalStateException("Gist API unexpected response: " + apiResponse.body()); + } - GistResponse gistResponse = null; + GistResponse gistResponse; try { - gistResponse = JSON.readValue(response.body(), GistResponse.class); + gistResponse = JSON.readValue(apiResponse.body(), GistResponse.class); } catch (JsonProcessingException e) { - throw new IllegalStateException("Couldn't parse response...", e); + LOGGER.warn("Couldn't parse response!", e); // cause exception doesn't show in gradle + // run: + // https://github.com/Together-Java/TJ-Bot/issues/490 + throw new IllegalStateException("Couldn't parse response!", e); } + return gistResponse.getHtmlUrl(); + } - String url = gistResponse.getHtmlUrl(); + private void sendResponse(@NotNull MessageReceivedEvent event, + @NotNull Message.Attachment attachment, @NotNull String url) { + Message message = event.getMessage(); + String replyContent = + "I uploaded your file as gist, it is much easier to read for everyone like that, especially for mobile users"; + String fileName = attachment.getFileName(); - message.reply( - "I uploaded your file as gist, it is much easier to read for everyone like that especially for mobile users!") + message.reply(replyContent) .setActionRow(Button.of(ButtonStyle.LINK, url, fileName)) .queue(); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java index d4d304948b..4cf9ba10e5 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java @@ -1,5 +1,6 @@ /** - * This package offers all the functionality for automatically uploading files to gist The core - * class is {@link org.togetherjava.tjbot.commands.filesharing.ShareLongAttachmentsMessageListener} + * This package offers all the functionality for automatically uploading files to sharing services. + * The core class is + * {@link org.togetherjava.tjbot.commands.filesharing.ShareLongAttachmentsMessageListener}. */ package org.togetherjava.tjbot.commands.filesharing; diff --git a/application/src/main/java/org/togetherjava/tjbot/config/Config.java b/application/src/main/java/org/togetherjava/tjbot/config/Config.java index fb4ef623b8..26c205e255 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/Config.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/Config.java @@ -14,6 +14,7 @@ */ public final class Config { private final String token; + private final String shareApiKey; private final String databasePath; private final String projectWebsite; private final String discordGuildInvite; @@ -31,6 +32,7 @@ public final class Config { @SuppressWarnings("ConstructorWithTooManyParameters") @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) private Config(@JsonProperty("token") String token, + @JsonProperty("shareApiKey") String shareApiKey, @JsonProperty("databasePath") String databasePath, @JsonProperty("projectWebsite") String projectWebsite, @JsonProperty("discordGuildInvite") String discordGuildInvite, @@ -45,6 +47,7 @@ private Config(@JsonProperty("token") String token, @JsonProperty("wolframAlphaAppId") String wolframAlphaAppId, @JsonProperty("helpSystem") HelpSystemConfig helpSystem) { this.token = token; + this.shareApiKey = shareApiKey; this.databasePath = databasePath; this.projectWebsite = projectWebsite; this.discordGuildInvite = discordGuildInvite; @@ -100,6 +103,15 @@ public String getToken() { return token; } + /** + * Gets the API Key of the upload service to upload pastes via the API + * + * @return the upload services API Key + */ + public String getShareApiKey() { + return shareApiKey; + } + /** * Gets the path where the database of the application is located at. * From 366d1151caade157ff20778ff0ff23a317b26109 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sat, 13 Aug 2022 16:23:43 +0200 Subject: [PATCH 05/20] added api key --- application/config.json.template | 1 + 1 file changed, 1 insertion(+) diff --git a/application/config.json.template b/application/config.json.template index 8238dba370..85aedf8770 100644 --- a/application/config.json.template +++ b/application/config.json.template @@ -1,5 +1,6 @@ { "token": "", + "shareApiKey": "", "databasePath": "local-database.db", "projectWebsite": "https://github.com/Together-Java/TJ-Bot", "discordGuildInvite": "https://discord.com/invite/XXFUXzK", From a65e584a120364c6710e4e4659af4e948b8230e6 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sat, 13 Aug 2022 16:37:18 +0200 Subject: [PATCH 06/20] Added default api key to config --- application/config.json.template | 2 +- .../ShareLongAttachmentsMessageListener.java | 6 +++--- .../java/org/togetherjava/tjbot/config/Config.java | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/application/config.json.template b/application/config.json.template index 85aedf8770..5b1ce0cae8 100644 --- a/application/config.json.template +++ b/application/config.json.template @@ -1,6 +1,6 @@ { "token": "", - "shareApiKey": "", + "gistApiKey": "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", "databasePath": "local-database.db", "projectWebsite": "https://github.com/Together-Java/TJ-Bot", "discordGuildInvite": "https://discord.com/invite/XXFUXzK", diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java index 69e426f93e..e46f453216 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java @@ -42,7 +42,7 @@ public final class ShareLongAttachmentsMessageListener extends MessageReceiverAd private final Set extensionFilter = Set.of("txt", "java", "gradle", "xml", "kt", "json", "fxml", "css", "c", "h", "cpp", "py", "yml"); - private final String API_KEY; + private final String gistApiKey; private static final String SHARE_API = "https://api.github.com/gists"; private static final HttpClient CLIENT = HttpClient.newHttpClient(); @@ -52,7 +52,7 @@ public final class ShareLongAttachmentsMessageListener extends MessageReceiverAd public ShareLongAttachmentsMessageListener(@NotNull Config config) { super(Pattern.compile(".*")); - API_KEY = config.getShareApiKey(); + gistApiKey = config.getGistApiKey(); isStagingChannelName = Pattern.compile(config.getHelpSystem().getStagingChannelPattern()) .asMatchPredicate(); isOverviewChannelName = Pattern.compile(config.getHelpSystem().getOverviewChannelPattern()) @@ -124,7 +124,7 @@ private void processAttachment(@NotNull MessageReceivedEvent event, HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(SHARE_API)) .header("Accept", "application/json") - .header("Authorization", "token " + API_KEY) + .header("Authorization", "token " + gistApiKey) .POST(HttpRequest.BodyPublishers.ofString(body)) .build(); diff --git a/application/src/main/java/org/togetherjava/tjbot/config/Config.java b/application/src/main/java/org/togetherjava/tjbot/config/Config.java index 26c205e255..e7fac15152 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/Config.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/Config.java @@ -14,7 +14,7 @@ */ public final class Config { private final String token; - private final String shareApiKey; + private final String gistApiKey; private final String databasePath; private final String projectWebsite; private final String discordGuildInvite; @@ -32,7 +32,7 @@ public final class Config { @SuppressWarnings("ConstructorWithTooManyParameters") @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) private Config(@JsonProperty("token") String token, - @JsonProperty("shareApiKey") String shareApiKey, + @JsonProperty("gistApiKey") String gistApiKey, @JsonProperty("databasePath") String databasePath, @JsonProperty("projectWebsite") String projectWebsite, @JsonProperty("discordGuildInvite") String discordGuildInvite, @@ -47,7 +47,7 @@ private Config(@JsonProperty("token") String token, @JsonProperty("wolframAlphaAppId") String wolframAlphaAppId, @JsonProperty("helpSystem") HelpSystemConfig helpSystem) { this.token = token; - this.shareApiKey = shareApiKey; + this.gistApiKey = gistApiKey; this.databasePath = databasePath; this.projectWebsite = projectWebsite; this.discordGuildInvite = discordGuildInvite; @@ -108,8 +108,8 @@ public String getToken() { * * @return the upload services API Key */ - public String getShareApiKey() { - return shareApiKey; + public String getGistApiKey() { + return gistApiKey; } /** From 9285fdc70fac363250af29f56c19cf7c687d9419 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sat, 13 Aug 2022 16:44:46 +0200 Subject: [PATCH 07/20] fixed api key --- application/config.json.template | 2 +- .../src/main/java/org/togetherjava/tjbot/config/Config.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/config.json.template b/application/config.json.template index 5b1ce0cae8..6c433a2043 100644 --- a/application/config.json.template +++ b/application/config.json.template @@ -1,6 +1,6 @@ { "token": "", - "gistApiKey": "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", + "gistApiKey": "", "databasePath": "local-database.db", "projectWebsite": "https://github.com/Together-Java/TJ-Bot", "discordGuildInvite": "https://discord.com/invite/XXFUXzK", diff --git a/application/src/main/java/org/togetherjava/tjbot/config/Config.java b/application/src/main/java/org/togetherjava/tjbot/config/Config.java index e7fac15152..a30c45ecd5 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/Config.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/Config.java @@ -104,7 +104,7 @@ public String getToken() { } /** - * Gets the API Key of the upload service to upload pastes via the API + * Gets the API Key of GitHub to upload pastes via the API. * * @return the upload services API Key */ From 9012162ffe8f319c9e8ace5113dacef4cbd9c27f Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sat, 13 Aug 2022 17:00:57 +0200 Subject: [PATCH 08/20] changed to record --- .../tjbot/commands/filesharing/GistFile.java | 12 +--- .../tjbot/commands/filesharing/GistFiles.java | 25 ++++----- .../commands/filesharing/GistRequest.java | 56 +++++++++++-------- 3 files changed, 46 insertions(+), 47 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java index 86b5cad272..cba4472b4e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java @@ -6,15 +6,5 @@ * @see Create a Gist via * API */ -final class GistFile { - - private @NotNull String content; - - public GistFile(@NotNull String content) { - this.content = content; - } - - public @NotNull String getContent() { - return this.content; - } +record GistFile(@NotNull String content) { } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java index 292c27edc3..469d6285c0 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java @@ -10,17 +10,16 @@ * @see Create a Gist via * API */ -final class GistFiles { - - @JsonIgnore - private Map nameToContent; - - public GistFiles(@NotNull Map nameToContent) { - this.nameToContent = nameToContent; - } - - @JsonAnyGetter - public @NotNull Map getFiles() { - return nameToContent; - } +record GistFiles(@NotNull @JsonIgnore @JsonAnyGetter Map nameToContent) { } + +/* + * final class GistFiles { + * + * @JsonIgnore private Map nameToContent; + * + * public GistFiles(@NotNull Map nameToContent) { this.nameToContent = + * nameToContent; } + * + * @JsonAnyGetter public @NotNull Map getFiles() { return nameToContent; } } + */ diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java index 73fecf0d84..2b40e7e46e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java @@ -3,29 +3,39 @@ import com.fasterxml.jackson.annotation.JsonProperty; import org.jetbrains.annotations.NotNull; -final class GistRequest { - - private String description; - @JsonProperty("public") - private boolean isPublic; - private GistFiles files; - - public GistRequest(@NotNull String description, @NotNull boolean isPublic, - @NotNull GistFiles files) { - this.description = description; - this.isPublic = isPublic; - this.files = files; - } +/** + * @see Create a Gist via + * API + */ +record GistRequest(@NotNull String description, @JsonProperty("public") boolean isPublic, + @NotNull GistFiles files) { +} - public @NotNull String getDescription() { - return description; - } +// final class GistRequest { +// +// private String description; +// @JsonProperty("public") +// private boolean isPublic; +// private GistFiles files; +// +// public GistRequest(@NotNull String description, @NotNull boolean isPublic, +// @NotNull GistFiles files) { +// this.description = description; +// this.isPublic = isPublic; +// this.files = files; +// } +// +// public @NotNull String getDescription() { +// return description; +// } +// +// public @NotNull boolean isPublic() { +// return isPublic; +// } +// +// public @NotNull GistFiles getFiles() { +// return files; +// } +// } - public @NotNull boolean isPublic() { - return isPublic; - } - public @NotNull GistFiles getFiles() { - return files; - } -} From e3dcc52c34fcc0eedbd8e2457702f96357e75e9a Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sat, 13 Aug 2022 17:02:43 +0200 Subject: [PATCH 09/20] removed comments --- .../tjbot/commands/filesharing/GistFiles.java | 11 ------- .../commands/filesharing/GistRequest.java | 29 ------------------- 2 files changed, 40 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java index 469d6285c0..a0f00a0593 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java @@ -12,14 +12,3 @@ */ record GistFiles(@NotNull @JsonIgnore @JsonAnyGetter Map nameToContent) { } - -/* - * final class GistFiles { - * - * @JsonIgnore private Map nameToContent; - * - * public GistFiles(@NotNull Map nameToContent) { this.nameToContent = - * nameToContent; } - * - * @JsonAnyGetter public @NotNull Map getFiles() { return nameToContent; } } - */ diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java index 2b40e7e46e..d1e1156547 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java @@ -10,32 +10,3 @@ record GistRequest(@NotNull String description, @JsonProperty("public") boolean isPublic, @NotNull GistFiles files) { } - -// final class GistRequest { -// -// private String description; -// @JsonProperty("public") -// private boolean isPublic; -// private GistFiles files; -// -// public GistRequest(@NotNull String description, @NotNull boolean isPublic, -// @NotNull GistFiles files) { -// this.description = description; -// this.isPublic = isPublic; -// this.files = files; -// } -// -// public @NotNull String getDescription() { -// return description; -// } -// -// public @NotNull boolean isPublic() { -// return isPublic; -// } -// -// public @NotNull GistFiles getFiles() { -// return files; -// } -// } - - From c0b88725d509766383f7beda592ec6fd3e05ea76 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sun, 14 Aug 2022 00:13:51 +0200 Subject: [PATCH 10/20] added multiple uploads to one gist --- .../togetherjava/tjbot/commands/Features.java | 4 +- ...r.java => FileSharingMessageListener.java} | 96 +++++++++---------- .../tjbot/commands/filesharing/GistFiles.java | 3 +- .../commands/filesharing/package-info.java | 3 +- 4 files changed, 48 insertions(+), 58 deletions(-) rename application/src/main/java/org/togetherjava/tjbot/commands/filesharing/{ShareLongAttachmentsMessageListener.java => FileSharingMessageListener.java} (61%) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java index d9ab95d566..33be7da19e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java @@ -3,7 +3,7 @@ import net.dv8tion.jda.api.JDA; import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.basic.*; -import org.togetherjava.tjbot.commands.filesharing.ShareLongAttachmentsMessageListener; +import org.togetherjava.tjbot.commands.filesharing.FileSharingMessageListener; import org.togetherjava.tjbot.commands.help.*; import org.togetherjava.tjbot.commands.mathcommands.TeXCommand; import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.WolframAlphaCommand; @@ -79,7 +79,7 @@ public enum Features { features.add(new SuggestionsUpDownVoter(config)); features.add(new ScamBlocker(actionsStore, scamHistoryStore, config)); features.add(new ImplicitAskListener(config, helpSystemHelper)); - features.add(new ShareLongAttachmentsMessageListener(config)); + features.add(new FileSharingMessageListener(config)); // Event receivers features.add(new RejoinModerationRoleListener(actionsStore, config)); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java similarity index 61% rename from application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java rename to application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java index e46f453216..e39bddd473 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/ShareLongAttachmentsMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java @@ -5,12 +5,11 @@ import net.dv8tion.jda.api.entities.ChannelType; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.ThreadChannel; +import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; import org.togetherjava.tjbot.config.Config; @@ -23,33 +22,29 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Predicate; import java.util.regex.Pattern; -/** - * Listener that receives all sent help messages and uploads them to a share service if the message - * contains a file with the given extension in the - * {@link ShareLongAttachmentsMessageListener#extensionFilter} - */ -public final class ShareLongAttachmentsMessageListener extends MessageReceiverAdapter { +public class FileSharingMessageListener extends MessageReceiverAdapter { private static final ObjectMapper JSON = new ObjectMapper(); - private static final Logger LOGGER = - LoggerFactory.getLogger(ShareLongAttachmentsMessageListener.class); - - private final Set extensionFilter = Set.of("txt", "java", "gradle", "xml", "kt", "json", - "fxml", "css", "c", "h", "cpp", "py", "yml"); private final String gistApiKey; private static final String SHARE_API = "https://api.github.com/gists"; private static final HttpClient CLIENT = HttpClient.newHttpClient(); + private final Set extensionFilter = Set.of("txt", "java", "gradle", "xml", "kt", "json", + "fxml", "css", "c", "h", "cpp", "py", "yml"); + private final Predicate isStagingChannelName; private final Predicate isOverviewChannelName; - public ShareLongAttachmentsMessageListener(@NotNull Config config) { + + public FileSharingMessageListener(@NotNull Config config) { super(Pattern.compile(".*")); gistApiKey = config.getGistApiKey(); @@ -61,7 +56,8 @@ public ShareLongAttachmentsMessageListener(@NotNull Config config) { @Override public void onMessageReceived(@NotNull MessageReceivedEvent event) { - if (event.getAuthor().isBot() || event.isWebhookMessage()) { + User author = event.getAuthor(); + if (author.isBot() || event.isWebhookMessage()) { return; } @@ -69,21 +65,34 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { return; } - event.getMessage().getAttachments().stream().filter(attachment -> { - String fileExtension = attachment.getFileExtension(); - if (fileExtension == null) { - return false; - } - return extensionFilter.contains(fileExtension); - }).forEach(attachment -> processAttachment(event, attachment)); + List attachments = + event.getMessage().getAttachments().stream().filter(attachment -> { + String extension = attachment.getFileExtension(); + if (extension == null) { + return false; + } + return extensionFilter.contains(extension); + }).toList(); + + processAttachments(event, attachments); } - private void processAttachment(@NotNull MessageReceivedEvent event, - @NotNull Message.Attachment attachment) { - attachment.retrieveInputStream() - .thenApply(this::readAttachment) - .thenApply(content -> uploadToSharingService(event, attachment, content)) - .thenAccept(url -> sendResponse(event, attachment, url)); + private void processAttachments(@NotNull MessageReceivedEvent event, + @NotNull List attachments) { + Map filesAsJson = new HashMap<>(); + + for (Message.Attachment attachment : attachments) { + attachment.retrieveInputStream() + .thenApply(this::readAttachment) + .thenAccept(content -> filesAsJson.put(createFileName(attachment), + new GistFile(content))) + .join(); + } + + GistFiles files = new GistFiles(filesAsJson); + GistRequest request = new GistRequest(event.getAuthor().getName(), false, files); + String url = uploadToGist(request); + sendResponse(event, url); } private @NotNull String readAttachment(@NotNull InputStream stream) { @@ -94,9 +103,7 @@ private void processAttachment(@NotNull MessageReceivedEvent event, } } - private @NotNull String uploadToSharingService(@NotNull MessageReceivedEvent event, - @NotNull Message.Attachment attachment, @NotNull String content) { - + private @NotNull String createFileName(@NotNull Message.Attachment attachment) { String fileName = attachment.getFileName(); String fileExtension = attachment.getFileExtension(); @@ -107,17 +114,14 @@ private void processAttachment(@NotNull MessageReceivedEvent event, } fileName = fileName.substring(0, fileName.lastIndexOf(".")) + "." + fileExtension; + return fileName; + } - GistFiles files = new GistFiles(Map.of(fileName, new GistFile(content))); - GistRequest jsonRequest = new GistRequest(event.getAuthor().getName(), false, files); - + private @NotNull String uploadToGist(@NotNull GistRequest jsonRequest) { String body; try { body = JSON.writeValueAsString(jsonRequest); } catch (JsonProcessingException e) { - LOGGER.warn("Couldn't parse json request!", e); // cause exception doesn't show in - // gradle run: - // https://github.com/Together-Java/TJ-Bot/issues/490 throw new IllegalStateException("Couldn't parse json request!", e); } @@ -141,10 +145,6 @@ private void processAttachment(@NotNull MessageReceivedEvent event, if (statusCode < HttpURLConnection.HTTP_OK || statusCode >= HttpURLConnection.HTTP_MULT_CHOICE) { - LOGGER.warn("Gist API unexpected response: {}", apiResponse.body()); // cause exception - // doesn't show in - // gradle run: - // https://github.com/Together-Java/TJ-Bot/issues/490 throw new IllegalStateException("Gist API unexpected response: " + apiResponse.body()); } @@ -152,24 +152,17 @@ private void processAttachment(@NotNull MessageReceivedEvent event, try { gistResponse = JSON.readValue(apiResponse.body(), GistResponse.class); } catch (JsonProcessingException e) { - LOGGER.warn("Couldn't parse response!", e); // cause exception doesn't show in gradle - // run: - // https://github.com/Together-Java/TJ-Bot/issues/490 throw new IllegalStateException("Couldn't parse response!", e); } return gistResponse.getHtmlUrl(); } - private void sendResponse(@NotNull MessageReceivedEvent event, - @NotNull Message.Attachment attachment, @NotNull String url) { + private void sendResponse(@NotNull MessageReceivedEvent event, @NotNull String url) { Message message = event.getMessage(); String replyContent = - "I uploaded your file as gist, it is much easier to read for everyone like that, especially for mobile users"; - String fileName = attachment.getFileName(); + "I uploaded your file(s) as gist, it is much easier to read for everyone like that, especially for mobile users"; - message.reply(replyContent) - .setActionRow(Button.of(ButtonStyle.LINK, url, fileName)) - .queue(); + message.reply(replyContent).setActionRow(Button.of(ButtonStyle.LINK, url, "gist")).queue(); } private boolean isHelpThread(@NotNull MessageReceivedEvent event) { @@ -182,5 +175,4 @@ private boolean isHelpThread(@NotNull MessageReceivedEvent event) { return isStagingChannelName.test(rootChannelName) || isOverviewChannelName.test(rootChannelName); } - } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java index a0f00a0593..3d3f8ca032 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java @@ -1,7 +1,6 @@ package org.togetherjava.tjbot.commands.filesharing; import com.fasterxml.jackson.annotation.JsonAnyGetter; -import com.fasterxml.jackson.annotation.JsonIgnore; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -10,5 +9,5 @@ * @see Create a Gist via * API */ -record GistFiles(@NotNull @JsonIgnore @JsonAnyGetter Map nameToContent) { +record GistFiles(@NotNull @JsonAnyGetter Map nameToContent) { } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java index 4cf9ba10e5..3eba1af69d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java @@ -1,6 +1,5 @@ /** * This package offers all the functionality for automatically uploading files to sharing services. - * The core class is - * {@link org.togetherjava.tjbot.commands.filesharing.ShareLongAttachmentsMessageListener}. + * The core class is {@link org.togetherjava.tjbot.commands.filesharing.FileSharingMessageListener}. */ package org.togetherjava.tjbot.commands.filesharing; From 67f48d1df6935175ddd532640e4c13f22b5d1c82 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sun, 14 Aug 2022 11:51:34 +0200 Subject: [PATCH 11/20] Worked on pr comments --- .../tjbot/commands/filesharing/FileSharingMessageListener.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java index e39bddd473..7e18a6962a 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java @@ -8,7 +8,6 @@ import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.interactions.components.buttons.Button; -import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; import org.togetherjava.tjbot.config.Config; @@ -162,7 +161,7 @@ private void sendResponse(@NotNull MessageReceivedEvent event, @NotNull String u String replyContent = "I uploaded your file(s) as gist, it is much easier to read for everyone like that, especially for mobile users"; - message.reply(replyContent).setActionRow(Button.of(ButtonStyle.LINK, url, "gist")).queue(); + message.reply(replyContent).setActionRow(Button.link(url, "gist")).queue(); } private boolean isHelpThread(@NotNull MessageReceivedEvent event) { From 49054ac7bfaf9accda144df29745b16708466b70 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sun, 14 Aug 2022 12:00:55 +0200 Subject: [PATCH 12/20] Fixed Sonarlint checks --- .../tjbot/commands/filesharing/FileSharingMessageListener.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java index 7e18a6962a..4eae244bdf 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java @@ -137,7 +137,8 @@ private void processAttachments(@NotNull MessageReceivedEvent event, } catch (IOException e) { throw new UncheckedIOException(e); } catch (InterruptedException e) { - throw new RuntimeException(e); + Thread.currentThread().interrupt(); + throw new IllegalStateException("HttpResponse interrupted!", e); } int statusCode = apiResponse.statusCode(); From 764380f61a38061e4606cd66c1807222afffd0b8 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Sun, 14 Aug 2022 12:28:47 +0200 Subject: [PATCH 13/20] Added documentation --- .../commands/filesharing/FileSharingMessageListener.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java index 4eae244bdf..364d59573d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java @@ -28,6 +28,11 @@ import java.util.function.Predicate; import java.util.regex.Pattern; +/** + * Listener that receives all sent help messages and uploads them to a share service if the message + * contains a file with the given extension in the + * {@link FileSharingMessageListener#extensionFilter} + */ public class FileSharingMessageListener extends MessageReceiverAdapter { private static final ObjectMapper JSON = new ObjectMapper(); From a58dde36b4f9924a6eca03bb29c2ab5fc35bafd5 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Mon, 15 Aug 2022 22:27:16 +0200 Subject: [PATCH 14/20] Worked on pr comments --- .../filesharing/DeleteGistCommand.java | 57 +++++++++++++++ .../FileSharingMessageListener.java | 69 +++++++++++-------- .../org/togetherjava/tjbot/config/Config.java | 3 + 3 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/filesharing/DeleteGistCommand.java diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/DeleteGistCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/DeleteGistCommand.java new file mode 100644 index 0000000000..caf76f8278 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/DeleteGistCommand.java @@ -0,0 +1,57 @@ +package org.togetherjava.tjbot.commands.filesharing; + +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.togetherjava.tjbot.commands.SlashCommandAdapter; +import org.togetherjava.tjbot.commands.SlashCommandVisibility; +import org.togetherjava.tjbot.config.Config; + +import java.util.function.Predicate; +import java.util.regex.Pattern; + +public final class DeleteGistCommand extends SlashCommandAdapter { + + private static final Logger logger = LoggerFactory.getLogger(DeleteGistCommand.class); + + private static final String MESSAGE_ID_OPTION = "message-id"; + + public DeleteGistCommand(@NotNull Config config) { + super("remove-gist", "Deletes gist's from auto file-sharing feature!", + SlashCommandVisibility.GUILD); + } + + @Override + public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + String messageId = event.getOption(MESSAGE_ID_OPTION).getAsString(); + + Message gistMessage = event.getMessageChannel().retrieveMessageById(messageId).complete(); + + String content = + "I uploaded your file(s) as gist, it is much easier to read for everyone like that, especially for mobile users"; + + if (!gistMessage.getAuthor().isBot() || !gistMessage.getContentRaw().equals(content)) { + return; + } + + User fileSender = gistMessage.getReferencedMessage().getAuthor(); + User user = event.getUser(); + + if (!user.equals(fileSender)) { + return; + } + + String url = gistMessage.getButtons() + .stream() + .filter(button -> button.getLabel().equals("gist")) + .toList() + .get(0) + .getUrl(); + url = url.replace("https://api.github.com/gists/", ""); + + // send api stuff to + } +} diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java index 364d59573d..ff7ad3c5ce 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java @@ -21,17 +21,15 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; import java.util.regex.Pattern; /** * Listener that receives all sent help messages and uploads them to a share service if the message * contains a file with the given extension in the - * {@link FileSharingMessageListener#extensionFilter} + * {@link FileSharingMessageListener#extensionFilter}. */ public class FileSharingMessageListener extends MessageReceiverAdapter { @@ -69,30 +67,42 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { return; } - List attachments = - event.getMessage().getAttachments().stream().filter(attachment -> { - String extension = attachment.getFileExtension(); - if (extension == null) { - return false; - } - return extensionFilter.contains(extension); - }).toList(); - processAttachments(event, attachments); + List attachments = event.getMessage() + .getAttachments() + .stream() + .filter(this::isAttachmentRelevant) + .toList(); + + CompletableFuture.runAsync(() -> processAttachments(event, attachments)); + } + + private boolean isAttachmentRelevant(@NotNull Message.Attachment attachment) { + String extension = attachment.getFileExtension(); + if (extension == null) { + return false; + } + return extensionFilter.contains(extension); } + private void processAttachments(@NotNull MessageReceivedEvent event, @NotNull List attachments) { - Map filesAsJson = new HashMap<>(); + Map filesAsJson = Collections.synchronizedMap(new HashMap<>()); + + List> tasks = new ArrayList<>(); for (Message.Attachment attachment : attachments) { - attachment.retrieveInputStream() + CompletableFuture task = attachment.retrieveInputStream() .thenApply(this::readAttachment) - .thenAccept(content -> filesAsJson.put(createFileName(attachment), - new GistFile(content))) - .join(); + .thenAccept( + content -> filesAsJson.put(getNameOf(attachment), new GistFile(content))); + + tasks.add(task); } + tasks.forEach(CompletableFuture::join); + GistFiles files = new GistFiles(filesAsJson); GistRequest request = new GistRequest(event.getAuthor().getName(), false, files); String url = uploadToGist(request); @@ -107,7 +117,7 @@ private void processAttachments(@NotNull MessageReceivedEvent event, } } - private @NotNull String createFileName(@NotNull Message.Attachment attachment) { + private @NotNull String getNameOf(@NotNull Message.Attachment attachment) { String fileName = attachment.getFileName(); String fileExtension = attachment.getFileExtension(); @@ -126,13 +136,14 @@ private void processAttachments(@NotNull MessageReceivedEvent event, try { body = JSON.writeValueAsString(jsonRequest); } catch (JsonProcessingException e) { - throw new IllegalStateException("Couldn't parse json request!", e); + throw new IllegalStateException( + "Attempting to upload a file to gist, but unable to create the JSON request.", + e); } HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(SHARE_API)) - .header("Accept", "application/json") - .header("Authorization", "token " + gistApiKey) + .headers("Accept", "application/json", "Authorization", "token " + gistApiKey) .POST(HttpRequest.BodyPublishers.ofString(body)) .build(); @@ -143,7 +154,8 @@ private void processAttachments(@NotNull MessageReceivedEvent event, throw new UncheckedIOException(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw new IllegalStateException("HttpResponse interrupted!", e); + throw new IllegalStateException( + "Attempting to upload a file to gist, but the request got interrupted.", e); } int statusCode = apiResponse.statusCode(); @@ -157,17 +169,18 @@ private void processAttachments(@NotNull MessageReceivedEvent event, try { gistResponse = JSON.readValue(apiResponse.body(), GistResponse.class); } catch (JsonProcessingException e) { - throw new IllegalStateException("Couldn't parse response!", e); + throw new IllegalStateException( + "Attempting to upload file to gist, but unable to parse its JSON response.", e); } return gistResponse.getHtmlUrl(); } private void sendResponse(@NotNull MessageReceivedEvent event, @NotNull String url) { Message message = event.getMessage(); - String replyContent = - "I uploaded your file(s) as gist, it is much easier to read for everyone like that, especially for mobile users"; + String messageContent = + "I uploaded your attachments as **gist**. That way, they are easier to read for everyone, especially mobile users 👍"; - message.reply(replyContent).setActionRow(Button.link(url, "gist")).queue(); + message.reply(messageContent).setActionRow(Button.link(url, "gist")).queue(); } private boolean isHelpThread(@NotNull MessageReceivedEvent event) { diff --git a/application/src/main/java/org/togetherjava/tjbot/config/Config.java b/application/src/main/java/org/togetherjava/tjbot/config/Config.java index a30c45ecd5..9888d12191 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/Config.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/Config.java @@ -107,6 +107,9 @@ public String getToken() { * Gets the API Key of GitHub to upload pastes via the API. * * @return the upload services API Key + * @see Create + * a GitHub key */ public String getGistApiKey() { return gistApiKey; From 66614b6367c1160247a01178e93e7a0a4cdc47c0 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Mon, 15 Aug 2022 22:29:07 +0200 Subject: [PATCH 15/20] Accidentally pushed --- .../filesharing/DeleteGistCommand.java | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 application/src/main/java/org/togetherjava/tjbot/commands/filesharing/DeleteGistCommand.java diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/DeleteGistCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/DeleteGistCommand.java deleted file mode 100644 index caf76f8278..0000000000 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/DeleteGistCommand.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.togetherjava.tjbot.commands.filesharing; - -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.togetherjava.tjbot.commands.SlashCommandAdapter; -import org.togetherjava.tjbot.commands.SlashCommandVisibility; -import org.togetherjava.tjbot.config.Config; - -import java.util.function.Predicate; -import java.util.regex.Pattern; - -public final class DeleteGistCommand extends SlashCommandAdapter { - - private static final Logger logger = LoggerFactory.getLogger(DeleteGistCommand.class); - - private static final String MESSAGE_ID_OPTION = "message-id"; - - public DeleteGistCommand(@NotNull Config config) { - super("remove-gist", "Deletes gist's from auto file-sharing feature!", - SlashCommandVisibility.GUILD); - } - - @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { - String messageId = event.getOption(MESSAGE_ID_OPTION).getAsString(); - - Message gistMessage = event.getMessageChannel().retrieveMessageById(messageId).complete(); - - String content = - "I uploaded your file(s) as gist, it is much easier to read for everyone like that, especially for mobile users"; - - if (!gistMessage.getAuthor().isBot() || !gistMessage.getContentRaw().equals(content)) { - return; - } - - User fileSender = gistMessage.getReferencedMessage().getAuthor(); - User user = event.getUser(); - - if (!user.equals(fileSender)) { - return; - } - - String url = gistMessage.getButtons() - .stream() - .filter(button -> button.getLabel().equals("gist")) - .toList() - .get(0) - .getUrl(); - url = url.replace("https://api.github.com/gists/", ""); - - // send api stuff to - } -} From 85d5f2a8a5b4821209f0848cb37b4e4da1fecad7 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Tue, 16 Aug 2022 21:32:35 +0200 Subject: [PATCH 16/20] pr comments From 045d7480a50c10aa0edeb3940407a005c32dda9a Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Wed, 17 Aug 2022 09:12:24 +0200 Subject: [PATCH 17/20] pr comments From 012085e40ffcd5c960617bbf079e2774bf9fac92 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Wed, 17 Aug 2022 10:19:54 +0200 Subject: [PATCH 18/20] pr comments --- .../tjbot/commands/filesharing/FileSharingMessageListener.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java index ff7ad3c5ce..1300b30387 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java @@ -143,7 +143,8 @@ private void processAttachments(@NotNull MessageReceivedEvent event, HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(SHARE_API)) - .headers("Accept", "application/json", "Authorization", "token " + gistApiKey) + .header("Accept", "application/json") + .header("Authorization", "token " + gistApiKey) .POST(HttpRequest.BodyPublishers.ofString(body)) .build(); From 641299cf9360e6a18069405e64027f2e13f24887 Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Wed, 17 Aug 2022 11:58:07 +0200 Subject: [PATCH 19/20] pr comments --- .../commands/filesharing/FileSharingMessageListener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java index 1300b30387..531a8793f8 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java @@ -23,6 +23,7 @@ import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; import java.util.regex.Pattern; @@ -35,10 +36,10 @@ public class FileSharingMessageListener extends MessageReceiverAdapter { private static final ObjectMapper JSON = new ObjectMapper(); - private final String gistApiKey; private static final String SHARE_API = "https://api.github.com/gists"; private static final HttpClient CLIENT = HttpClient.newHttpClient(); + private final String gistApiKey; private final Set extensionFilter = Set.of("txt", "java", "gradle", "xml", "kt", "json", "fxml", "css", "c", "h", "cpp", "py", "yml"); @@ -89,7 +90,7 @@ private boolean isAttachmentRelevant(@NotNull Message.Attachment attachment) { private void processAttachments(@NotNull MessageReceivedEvent event, @NotNull List attachments) { - Map filesAsJson = Collections.synchronizedMap(new HashMap<>()); + Map filesAsJson = new ConcurrentHashMap<>(); List> tasks = new ArrayList<>(); for (Message.Attachment attachment : attachments) { From 0a366efa84a77e32d0e608603e7e8720dd1d892d Mon Sep 17 00:00:00 2001 From: SquidXTV Date: Fri, 19 Aug 2022 11:51:55 +0200 Subject: [PATCH 20/20] pr comments --- .../FileSharingMessageListener.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java index 531a8793f8..1e1c0a3639 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java @@ -9,6 +9,8 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.interactions.components.buttons.Button; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; import org.togetherjava.tjbot.config.Config; @@ -34,6 +36,7 @@ */ public class FileSharingMessageListener extends MessageReceiverAdapter { + private static final Logger LOGGER = LoggerFactory.getLogger(FileSharingMessageListener.class); private static final ObjectMapper JSON = new ObjectMapper(); private static final String SHARE_API = "https://api.github.com/gists"; @@ -75,7 +78,13 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { .filter(this::isAttachmentRelevant) .toList(); - CompletableFuture.runAsync(() -> processAttachments(event, attachments)); + CompletableFuture.runAsync(() -> { + try { + processAttachments(event, attachments); + } catch (Exception e) { + LOGGER.error("Unknown error while processing attachments", e); + } + }); } private boolean isAttachmentRelevant(@NotNull Message.Attachment attachment) { @@ -90,21 +99,21 @@ private boolean isAttachmentRelevant(@NotNull Message.Attachment attachment) { private void processAttachments(@NotNull MessageReceivedEvent event, @NotNull List attachments) { - Map filesAsJson = new ConcurrentHashMap<>(); + Map nameToFile = new ConcurrentHashMap<>(); List> tasks = new ArrayList<>(); for (Message.Attachment attachment : attachments) { CompletableFuture task = attachment.retrieveInputStream() .thenApply(this::readAttachment) .thenAccept( - content -> filesAsJson.put(getNameOf(attachment), new GistFile(content))); + content -> nameToFile.put(getNameOf(attachment), new GistFile(content))); tasks.add(task); } tasks.forEach(CompletableFuture::join); - GistFiles files = new GistFiles(filesAsJson); + GistFiles files = new GistFiles(nameToFile); GistRequest request = new GistRequest(event.getAuthor().getName(), false, files); String url = uploadToGist(request); sendResponse(event, url); @@ -128,7 +137,13 @@ private void processAttachments(@NotNull MessageReceivedEvent event, fileExtension = "xml"; } - fileName = fileName.substring(0, fileName.lastIndexOf(".")) + "." + fileExtension; + int extensionIndex = fileName.lastIndexOf('.'); + if (extensionIndex != -1) { + fileName = fileName.substring(0, extensionIndex); + } + + fileName += "." + fileExtension; + return fileName; }