From 6397008426eca45f6ada92c4f0270121f51e5353 Mon Sep 17 00:00:00 2001 From: ascsolleo Date: Mon, 23 Feb 2026 13:51:33 +0200 Subject: [PATCH 1/4] fix: allow forwarded messages with media in media-only channels --- .../mediaonly/MediaOnlyChannelListener.java | 46 ++++++++++++++++++- .../MediaOnlyChannelListenerTest.java | 46 +++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java index 11f666beaa..ec9ea1196d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java @@ -4,6 +4,7 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageType; +import net.dv8tion.jda.api.entities.messages.MessageSnapshot; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; @@ -13,6 +14,7 @@ import org.togetherjava.tjbot.features.MessageReceiverAdapter; import java.awt.Color; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -51,9 +53,49 @@ public void onMessageReceived(MessageReceivedEvent event) { } } +// private boolean messageHasNoMediaAttached(Message message) { +// return message.getAttachments().isEmpty() && message.getEmbeds().isEmpty() +// && !message.getContentRaw().contains("http"); +// } + + /** + * Checks whether the given message has no media attached. + *

+ * A message is considered to have media if it contains attachments, embeds, + * or a URL in its text content. For forwarded messages, the snapshots are also + * checked for media. + * + * @param message the message to check + * @return {@code true} if the message has no media, {@code false} otherwise + */ private boolean messageHasNoMediaAttached(Message message) { - return message.getAttachments().isEmpty() && message.getEmbeds().isEmpty() - && !message.getContentRaw().contains("http"); + if (hasMedia(message.getAttachments(), message.getEmbeds(), message.getContentRaw())) { + return false; + } + // checks forwarded snapshots + for (MessageSnapshot snapshot : message.getMessageSnapshots()) { + if (hasMedia(snapshot.getAttachments(), snapshot.getEmbeds(), snapshot.getContentRaw())) { + return false; + } + } + return true; + } + /** + * Checks whether the given content contains any media. + *

+ * Media is considered present if there are attachments, embeds, + * or a URL (identified by {@code "http"}) in the text content. + * + * @param attachments the attachments of the message or snapshot + * @param embeds the embeds of the message or snapshot + * @param content the raw text content of the message or snapshot + */ + + private boolean hasMedia(List attachments, + List embeds, String content) { + return !attachments.isEmpty() + || !embeds.isEmpty() + || content.contains("http"); } private MessageCreateData createNotificationMessage(Message message) { diff --git a/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java b/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java index c42bba88bf..6ab6f8e9f3 100644 --- a/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java @@ -4,6 +4,7 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.channel.ChannelType; +import net.dv8tion.jda.api.entities.messages.MessageSnapshot; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; import net.dv8tion.jda.api.utils.messages.MessageCreateData; @@ -112,4 +113,49 @@ private MessageReceivedEvent sendMessage(MessageCreateData message, mediaOnlyChannelListener.onMessageReceived(event); return event; } + + + @Test + void keepsForwardedMessageWithAttachment() { + // GIVEN a forwarded message that contains an attachment inside the snapshot + MessageCreateData message = new MessageCreateBuilder().setContent("any").build(); + + MessageSnapshot snapshot = mock(MessageSnapshot.class); + when(snapshot.getAttachments()).thenReturn(List.of(mock(Message.Attachment.class))); + when(snapshot.getEmbeds()).thenReturn(List.of()); + when(snapshot.getContentRaw()).thenReturn(""); + + // WHEN sending the forwarded message + MessageReceivedEvent event = sendMessageWithSnapshots(message, List.of(snapshot)); + + // THEN it does not get deleted + verify(event.getMessage(), never()).delete(); + } + + @Test + void deletesForwardedMessageWithoutMedia() { + // GIVEN a forwarded message that contains no media inside the snapshot + MessageCreateData message = new MessageCreateBuilder().setContent("any").build(); + + MessageSnapshot snapshot = mock(MessageSnapshot.class); + when(snapshot.getAttachments()).thenReturn(List.of()); + when(snapshot.getEmbeds()).thenReturn(List.of()); + when(snapshot.getContentRaw()).thenReturn("just some text, no media"); + + // WHEN sending the forwarded message + MessageReceivedEvent event = sendMessageWithSnapshots(message, List.of(snapshot)); + + // THEN it gets deleted + verify(event.getMessage()).delete(); + } + + // Добавить этот вспомогательный метод рядом с существующим sendMessage(): + private MessageReceivedEvent sendMessageWithSnapshots(MessageCreateData message, + List snapshots) { + MessageReceivedEvent event = + jdaTester.createMessageReceiveEvent(message, List.of(), ChannelType.TEXT); + when(event.getMessage().getMessageSnapshots()).thenReturn(snapshots); + mediaOnlyChannelListener.onMessageReceived(event); + return event; + } } From 1fa9e39244aa2e5adcd195219c0b5724bc2f246d Mon Sep 17 00:00:00 2001 From: ascsolleo Date: Mon, 23 Feb 2026 16:47:41 +0200 Subject: [PATCH 2/4] fix: address review comments --- .../mediaonly/MediaOnlyChannelListener.java | 16 +++------------- .../mediaonly/MediaOnlyChannelListenerTest.java | 1 - 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java index ec9ea1196d..a6d59111a6 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java @@ -53,11 +53,6 @@ public void onMessageReceived(MessageReceivedEvent event) { } } -// private boolean messageHasNoMediaAttached(Message message) { -// return message.getAttachments().isEmpty() && message.getEmbeds().isEmpty() -// && !message.getContentRaw().contains("http"); -// } - /** * Checks whether the given message has no media attached. *

@@ -72,13 +67,9 @@ private boolean messageHasNoMediaAttached(Message message) { if (hasMedia(message.getAttachments(), message.getEmbeds(), message.getContentRaw())) { return false; } - // checks forwarded snapshots - for (MessageSnapshot snapshot : message.getMessageSnapshots()) { - if (hasMedia(snapshot.getAttachments(), snapshot.getEmbeds(), snapshot.getContentRaw())) { - return false; - } - } - return true; + + return message.getMessageSnapshots().stream().noneMatch(snapshot -> + hasMedia(snapshot.getAttachments(), snapshot.getEmbeds(), snapshot.getContentRaw())); } /** * Checks whether the given content contains any media. @@ -90,7 +81,6 @@ private boolean messageHasNoMediaAttached(Message message) { * @param embeds the embeds of the message or snapshot * @param content the raw text content of the message or snapshot */ - private boolean hasMedia(List attachments, List embeds, String content) { return !attachments.isEmpty() diff --git a/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java b/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java index 6ab6f8e9f3..6fa1807f5e 100644 --- a/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java @@ -149,7 +149,6 @@ void deletesForwardedMessageWithoutMedia() { verify(event.getMessage()).delete(); } - // Добавить этот вспомогательный метод рядом с существующим sendMessage(): private MessageReceivedEvent sendMessageWithSnapshots(MessageCreateData message, List snapshots) { MessageReceivedEvent event = From 2725aa10cf25e605985646fcf91ef11b9df8f6c2 Mon Sep 17 00:00:00 2001 From: ascsolleo Date: Tue, 24 Feb 2026 10:47:55 +0200 Subject: [PATCH 3/4] fix: remove unused import --- .../tjbot/features/mediaonly/MediaOnlyChannelListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java index a6d59111a6..9511ae4e23 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java @@ -4,7 +4,6 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.MessageType; -import net.dv8tion.jda.api.entities.messages.MessageSnapshot; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder; From 6e21cf9331a57660ad9ecd3ca96158f8df26a63a Mon Sep 17 00:00:00 2001 From: ascsolleo Date: Tue, 24 Feb 2026 13:02:46 +0200 Subject: [PATCH 4/4] fix: apply code formatting --- .../mediaonly/MediaOnlyChannelListener.java | 24 +++++++++---------- .../MediaOnlyChannelListenerTest.java | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java index 9511ae4e23..083c3add07 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListener.java @@ -55,9 +55,8 @@ public void onMessageReceived(MessageReceivedEvent event) { /** * Checks whether the given message has no media attached. *

- * A message is considered to have media if it contains attachments, embeds, - * or a URL in its text content. For forwarded messages, the snapshots are also - * checked for media. + * A message is considered to have media if it contains attachments, embeds, or a URL in its + * text content. For forwarded messages, the snapshots are also checked for media. * * @param message the message to check * @return {@code true} if the message has no media, {@code false} otherwise @@ -67,24 +66,25 @@ private boolean messageHasNoMediaAttached(Message message) { return false; } - return message.getMessageSnapshots().stream().noneMatch(snapshot -> - hasMedia(snapshot.getAttachments(), snapshot.getEmbeds(), snapshot.getContentRaw())); + return message.getMessageSnapshots() + .stream() + .noneMatch(snapshot -> hasMedia(snapshot.getAttachments(), snapshot.getEmbeds(), + snapshot.getContentRaw())); } + /** * Checks whether the given content contains any media. *

- * Media is considered present if there are attachments, embeds, - * or a URL (identified by {@code "http"}) in the text content. + * Media is considered present if there are attachments, embeds, or a URL (identified by + * {@code "http"}) in the text content. * * @param attachments the attachments of the message or snapshot * @param embeds the embeds of the message or snapshot * @param content the raw text content of the message or snapshot */ - private boolean hasMedia(List attachments, - List embeds, String content) { - return !attachments.isEmpty() - || !embeds.isEmpty() - || content.contains("http"); + private boolean hasMedia(List attachments, List embeds, + String content) { + return !attachments.isEmpty() || !embeds.isEmpty() || content.contains("http"); } private MessageCreateData createNotificationMessage(Message message) { diff --git a/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java b/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java index 6fa1807f5e..89d36fcdf4 100644 --- a/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/features/mediaonly/MediaOnlyChannelListenerTest.java @@ -150,7 +150,7 @@ void deletesForwardedMessageWithoutMedia() { } private MessageReceivedEvent sendMessageWithSnapshots(MessageCreateData message, - List snapshots) { + List snapshots) { MessageReceivedEvent event = jdaTester.createMessageReceiveEvent(message, List.of(), ChannelType.TEXT); when(event.getMessage().getMessageSnapshots()).thenReturn(snapshots);