Skip to content
3 changes: 2 additions & 1 deletion application/config.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@
"Other"
],
"categoryRoleSuffix": " - Helper"
}
},
"mediaOnlyChannelPattern": "memes"
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.togetherjava.tjbot.commands.help.*;
import org.togetherjava.tjbot.commands.mathcommands.TeXCommand;
import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.WolframAlphaCommand;
import org.togetherjava.tjbot.commands.meme.MemeListener;
import org.togetherjava.tjbot.commands.moderation.*;
import org.togetherjava.tjbot.commands.moderation.scam.ScamBlocker;
import org.togetherjava.tjbot.commands.moderation.scam.ScamHistoryPurgeRoutine;
Expand Down Expand Up @@ -80,6 +81,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 MemeListener(config));
features.add(new FileSharingMessageListener(config));

// Event receivers
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.togetherjava.tjbot.commands.meme;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import org.jetbrains.annotations.NotNull;
import org.togetherjava.tjbot.commands.MessageReceiverAdapter;
import org.togetherjava.tjbot.config.Config;

import java.util.regex.Pattern;

/**
* Listener that receives all sent messages from the Meme channel, checks if the message has media
* attched.
* <p>
* If there was no media attached, delete the messagen and send the User a DM, telling what they did
* wrong.
*/
public final class MemeListener extends MessageReceiverAdapter {

/**
* Creates a MemeListener to receive all message sent in Memes channel.
*
* @param config the config to use for this
*/
public MemeListener(@NotNull Config config) {
super(Pattern.compile(config.getMediaOnlyChannelPattern()));
}


@Override
public void onMessageReceived(@NotNull MessageReceivedEvent event) {
if (event.getAuthor().isBot() || event.isWebhookMessage()) {
return;
}
boolean messageHasNoMediaAttached = messageHasNoMediaAttached(event);
if (messageHasNoMediaAttached) {
deleteMessage(event).flatMap(any -> dmUser(event)).queue();
}
}

private static boolean messageHasNoMediaAttached(MessageReceivedEvent event) {
Message message = event.getMessage();
return message.getAttachments().isEmpty() && message.getEmbeds().isEmpty();
}

private AuditableRestAction<Void> deleteMessage(@NotNull MessageReceivedEvent event) {
return event.getMessage().delete();
}

private RestAction<Message> dmUser(@NotNull MessageReceivedEvent event) {
return dmUser(event.getMessage(), event.getAuthor().getIdLong(), event.getJDA());
}

private RestAction<Message> dmUser(Message sentMessage, long userId, @NotNull JDA jda) {
String contentDisplay = sentMessage.getContentDisplay();
String dmMessage =
("Hey there, your were posting a Meme without a Media attached: '%s' please attach some media (URL or other Media) to your message")
.formatted(contentDisplay);
return jda.openPrivateChannelById(userId)
.flatMap(channel -> channel.sendMessage(dmMessage));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public final class Config {
private final String wolframAlphaAppId;
private final HelpSystemConfig helpSystem;

private final String mediaOnlyChannelPattern;

@SuppressWarnings("ConstructorWithTooManyParameters")
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
private Config(@JsonProperty("token") String token,
Expand All @@ -45,7 +47,8 @@ private Config(@JsonProperty("token") String token,
@JsonProperty("quarantinedRolePattern") String quarantinedRolePattern,
@JsonProperty("scamBlocker") ScamBlockerConfig scamBlocker,
@JsonProperty("wolframAlphaAppId") String wolframAlphaAppId,
@JsonProperty("helpSystem") HelpSystemConfig helpSystem) {
@JsonProperty("helpSystem") HelpSystemConfig helpSystem,
@JsonProperty("memeChannelPattern") String mediaOnlyChannelPattern) {
this.token = token;
this.gistApiKey = gistApiKey;
this.databasePath = databasePath;
Expand All @@ -61,6 +64,7 @@ private Config(@JsonProperty("token") String token,
this.scamBlocker = scamBlocker;
this.wolframAlphaAppId = wolframAlphaAppId;
this.helpSystem = helpSystem;
this.mediaOnlyChannelPattern = mediaOnlyChannelPattern;
}

/**
Expand Down Expand Up @@ -216,4 +220,13 @@ public String getQuarantinedRolePattern() {
public @NotNull HelpSystemConfig getHelpSystem() {
return helpSystem;
}

/**
* Gets the REGEX pattern used to identify the channel that is supposed to contain memes.
*
* @return the channel name pattern
*/
public @NotNull String getMediaOnlyChannelPattern() {
return mediaOnlyChannelPattern;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.togetherjava.tjbot.commands.meme;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import net.dv8tion.jda.internal.JDAImpl;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.togetherjava.tjbot.config.Config;

import java.util.Collections;
import java.util.List;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class MemeListenerTest {

private final JDA api = mock(JDA.class);

private final JDAImpl jda = mock(JDAImpl.class);

private final Message message = mock(Message.class);
private final long responseNumber = 1L;
private final User user = mock(User.class);

private MemeListener memeListener;

@BeforeEach
void setUp() {
Config config = mock(Config.class);
when(config.getMediaOnlyChannelPattern()).thenReturn("memes");
memeListener = new MemeListener(config);
}

@Test
void validMemePostWithAttachment() {
Message.Attachment attachment = new Message.Attachment(1L, null, null, "TEST",
"Test ContentType", null, 1, 1, 1, false, jda);
List<Message.Attachment> attachments = Collections.singletonList(attachment);

when(message.getAuthor()).thenReturn(user);
when(message.getAttachments()).thenReturn(attachments);
when(user.isBot()).thenReturn(false);

MessageReceivedEvent messageReceivedEvent =
new MessageReceivedEvent(api, responseNumber, message);
memeListener.onMessageReceived(messageReceivedEvent);
}

@Test
void validMemePostWithUrlEmbedded() {
MessageEmbed messageEmbed = new MessageEmbed("https://9gag.com/gag/a61A238", "Test", "Test",
EmbedType.LINK, null, 1, null, null, null, null, null, null, null);
List<MessageEmbed> messageEmbeds = Collections.singletonList(messageEmbed);

when(message.getAuthor()).thenReturn(user);
when(message.getEmbeds()).thenReturn(messageEmbeds);
when(user.isBot()).thenReturn(false);

MessageReceivedEvent messageReceivedEvent =
new MessageReceivedEvent(api, responseNumber, message);
memeListener.onMessageReceived(messageReceivedEvent);
}

@Test
@SuppressWarnings({"unchecked", "rawtypes"})
void unvalidMemePostWithOnlyText() {
AuditableRestAction<Void> auditableRestAction = mock(AuditableRestAction.class);
RestAction<PrivateChannel> restActionPrivateChannel = mock(RestAction.class);
RestAction restActionMessage = mock(RestAction.class);

when(message.getAuthor()).thenReturn(user);
when(message.getAttachments()).thenReturn(Collections.emptyList());
when(message.delete()).thenReturn(auditableRestAction);
when(user.isBot()).thenReturn(false);
when(api.openPrivateChannelById(0)).thenReturn(restActionPrivateChannel);
when(restActionPrivateChannel.flatMap(any())).thenReturn(restActionMessage);
when(auditableRestAction.flatMap(any())).thenReturn(restActionMessage);

MessageReceivedEvent messageReceivedEvent =
new MessageReceivedEvent(api, responseNumber, message);
memeListener.onMessageReceived(messageReceivedEvent);
}

}