Compare commits

...

2 Commits

Author SHA1 Message Date
Sheldan
58632bcf9d [AB-xxx] preparing for minor release 2025-02-03 23:05:44 +01:00
Sheldan
592ac01bfa [AB-xxx] changes for newer JDA version 2025-02-03 23:01:52 +01:00
11 changed files with 4 additions and 377 deletions

2
.env
View File

@@ -1,2 +1,2 @@
REGISTRY_PREFIX=harbor.sheldan.dev/abstracto/
VERSION=1.5.60
VERSION=1.6.0

View File

@@ -39,6 +39,7 @@ jobs:
git-release-bot-name: "release-bot"
git-release-bot-email: "release-bot@sheldan.dev"
release-branch-name: master
version-minor: true
maven-args: "-Dmaven.javadoc.skip=true -s settings.xml -DskipTests"
access-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install node dependencies and build

View File

@@ -1,66 +0,0 @@
package dev.sheldan.abstracto.repostdetection.listener;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageEmbeddedListener;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.repostdetection.config.RepostDetectionFeatureDefinition;
import dev.sheldan.abstracto.repostdetection.service.RepostCheckChannelService;
import dev.sheldan.abstracto.repostdetection.service.RepostService;
import dev.sheldan.abstracto.repostdetection.service.management.PostedImageManagement;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.EmbedType;
import net.dv8tion.jda.api.entities.MessageEmbed;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
@Slf4j
public class RepostEmbedListener implements AsyncMessageEmbeddedListener {
@Autowired
private RepostCheckChannelService repostCheckChannelService;
@Autowired
private RepostService repostService;
@Autowired
private PostedImageManagement repostManagement;
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private ChannelService channelService;
@Override
public DefaultListenerResult execute(GuildMessageEmbedEventModel eventModel) {
AChannel channel = channelManagementService.loadChannel(eventModel.getChannelId());
if(repostCheckChannelService.duplicateCheckEnabledForChannel(channel)) {
if(repostManagement.messageEmbedsHaveBeenCovered(eventModel.getMessageId())) {
log.info("The embeds of the message {} in channel {} in server {} have already been covered by repost check -- ignoring.",
eventModel.getMessageId(), eventModel.getChannelId(), eventModel.getServerId());
return DefaultListenerResult.IGNORED;
}
channelService.retrieveMessageInChannel(eventModel.getServerId(), eventModel.getChannelId(), eventModel.getMessageId()).thenAccept(message -> {
List<MessageEmbed> imageEmbeds = eventModel.getEmbeds().stream().filter(messageEmbed -> messageEmbed.getType().equals(EmbedType.IMAGE)).collect(Collectors.toList());
if(!imageEmbeds.isEmpty()) {
repostService.processMessageEmbedsRepostCheck(imageEmbeds, message);
}
});
}
return DefaultListenerResult.PROCESSED;
}
@Override
public FeatureDefinition getFeature() {
return RepostDetectionFeatureDefinition.REPOST_DETECTION;
}
}

View File

@@ -1,137 +0,0 @@
package dev.sheldan.abstracto.repostdetection.listener;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.repostdetection.service.RepostCheckChannelService;
import dev.sheldan.abstracto.repostdetection.service.RepostService;
import dev.sheldan.abstracto.repostdetection.service.management.PostedImageManagement;
import net.dv8tion.jda.api.entities.EmbedType;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageEmbed;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class RepostEmbedListenerTest {
@InjectMocks
private RepostEmbedListener testUnit;
@Mock
private RepostCheckChannelService repostCheckChannelService;
@Mock
private RepostService repostService;
@Mock
private PostedImageManagement repostManagement;
@Mock
private ChannelManagementService channelManagementService;
@Mock
private ChannelService channelService;
@Mock
private GuildMessageEmbedEventModel model;
@Mock
private TextChannel textChannel;
@Mock
private Message message;
@Mock
private AChannel channel;
@Captor
private ArgumentCaptor<List<MessageEmbed>> embedListsParameterCaptor;
private static final Long MESSAGE_ID = 1L;
private static final Long CHANNEL_ID = 2L;
private static final Long SERVER_ID = 3L;
@Test
public void testExecuteCheckDisabled() {
when(model.getChannelId()).thenReturn(CHANNEL_ID);
testUnit.execute(model);
verify(repostManagement, times(0)).messageEmbedsHaveBeenCovered(anyLong());
}
@Test
public void testExecuteEmbedsHaveBeenCovered() {
channelSetup();
setupMessageHasBeenCovered(true);
testUnit.execute(model);
verify(repostService, times(0)).processMessageEmbedsRepostCheck(anyList(), any(Message.class));
}
@Test
public void testExecuteNoEmbeds() {
channelSetup();
setupMessageHasBeenCovered(false);
when(channelService.retrieveMessageInChannel(SERVER_ID, CHANNEL_ID, MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(message));
testUnit.execute(model);
verify(repostService, times(0)).processMessageEmbedsRepostCheck(anyList(), any(Message.class));
}
@Test
public void testExecuteOneImageEmbed() {
channelSetup();
setupMessageHasBeenCovered(false);
MessageEmbed imageEmbed = Mockito.mock(MessageEmbed.class);
when(imageEmbed.getType()).thenReturn(EmbedType.IMAGE);
when(model.getEmbeds()).thenReturn(Arrays.asList(imageEmbed));
when(channelService.retrieveMessageInChannel(SERVER_ID, CHANNEL_ID, MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(message));
testUnit.execute(model);
verifySingleEmbedProcessed(imageEmbed);
}
@Test
public void testExecuteMultipleEmbedsOneImage() {
channelSetup();
setupMessageHasBeenCovered(false);
MessageEmbed imageEmbed = Mockito.mock(MessageEmbed.class);
MessageEmbed nonImageEmbed = Mockito.mock(MessageEmbed.class);
when(imageEmbed.getType()).thenReturn(EmbedType.IMAGE);
when(nonImageEmbed.getType()).thenReturn(EmbedType.LINK);
when(model.getEmbeds()).thenReturn(Arrays.asList(imageEmbed, nonImageEmbed));
when(channelService.retrieveMessageInChannel(SERVER_ID, CHANNEL_ID, MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(message));
testUnit.execute(model);
verifySingleEmbedProcessed(imageEmbed);
}
private void setupMessageHasBeenCovered(boolean covered) {
when(model.getMessageId()).thenReturn(MESSAGE_ID);
when(repostManagement.messageEmbedsHaveBeenCovered(MESSAGE_ID)).thenReturn(covered);
}
private void verifySingleEmbedProcessed(MessageEmbed imageEmbed) {
verify(repostService, times(1)).processMessageEmbedsRepostCheck(embedListsParameterCaptor.capture(), eq(message));
List<MessageEmbed> embeds = embedListsParameterCaptor.getValue();
Assert.assertEquals(1, embeds.size());
Assert.assertEquals(imageEmbed, embeds.get(0));
}
private void channelSetup() {
when(model.getChannelId()).thenReturn(CHANNEL_ID);
when(model.getServerId()).thenReturn(SERVER_ID);
when(channelManagementService.loadChannel(CHANNEL_ID)).thenReturn(channel);
when(repostCheckChannelService.duplicateCheckEnabledForChannel(channel)).thenReturn(true);
}
}

View File

@@ -52,11 +52,6 @@ public class ListenerExecutorConfig {
return executorService.setupExecutorFor("messageReceivedListener");
}
@Bean(name = "messageEmbeddedExecutor")
public TaskExecutor messageEmbeddedExecutor() {
return executorService.setupExecutorFor("messageEmbeddedListener");
}
@Bean(name = "messageUpdatedExecutor")
public TaskExecutor messageUpdatedExecutor() {
return executorService.setupExecutorFor("messageUpdatedListener");

View File

@@ -1,52 +0,0 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.listener.ListenerService;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.message.MessageEmbedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.List;
@Component
@Slf4j
public class AsyncMessageEmbeddedListenerBean extends ListenerAdapter {
@Autowired(required = false)
private List<AsyncMessageEmbeddedListener> listenerList;
@Autowired
@Qualifier("messageEmbeddedExecutor")
private TaskExecutor messageEmbeddedListener;
@Autowired
private AsyncMessageEmbeddedListenerBean self;
@Autowired
private ListenerService listenerService;
@Override
@Transactional
public void onMessageEmbed(@Nonnull MessageEmbedEvent event) {
if(listenerList == null) return;
GuildMessageEmbedEventModel model = getModel(event);
listenerList.forEach(leaveListener -> listenerService.executeFeatureAwareListener(leaveListener, model, messageEmbeddedListener));
}
private GuildMessageEmbedEventModel getModel(MessageEmbedEvent event) {
return GuildMessageEmbedEventModel
.builder()
.channelId(event.getChannel().getIdLong())
.serverId(event.getGuild().getIdLong())
.embeds(event.getMessageEmbeds())
.messageId(event.getMessageIdLong())
.build();
}
}

View File

@@ -1,76 +0,0 @@
package dev.sheldan.abstracto.core.listener.sync.jda;
import dev.sheldan.abstracto.core.command.service.ExceptionService;
import dev.sheldan.abstracto.core.listener.ListenerService;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.MessageCache;
import dev.sheldan.abstracto.core.utils.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.message.MessageEmbedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import java.util.List;
@Component
@Slf4j
public class MessageEmbeddedListenerBean extends ListenerAdapter {
@Autowired
private MessageCache messageCache;
@Autowired(required = false)
private List<MessageEmbeddedListener> listenerList;
@Autowired
private FeatureConfigService featureConfigService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private BotService botService;
@Autowired
private ExceptionService exceptionService;
@Autowired
private ListenerService listenerService;
@Override
@Transactional
public void onMessageEmbed(@Nonnull MessageEmbedEvent event) {
if(listenerList == null) return;
GuildMessageEmbedEventModel model = buildModel(event);
listenerList.forEach(messageReceivedListener -> listenerService.executeFeatureAwareListener(messageReceivedListener, model));
}
private GuildMessageEmbedEventModel buildModel(MessageEmbedEvent event) {
return GuildMessageEmbedEventModel
.builder()
.channelId(event.getChannel().getIdLong())
.serverId(event.getGuild().getIdLong())
.embeds(event.getMessageEmbeds())
.messageId(event.getMessageIdLong())
.build();
}
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE)
public void executeIndividualGuildMessageReceivedListener(GuildMessageEmbedEventModel model, MessageEmbeddedListener messageReceivedListener) {
messageReceivedListener.execute(model);
}
@PostConstruct
public void postConstruct() {
BeanUtils.sortPrioritizedListeners(listenerList);
}
}

View File

@@ -1,8 +0,0 @@
package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.FeatureAwareListener;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
public interface AsyncMessageEmbeddedListener extends FeatureAwareListener<GuildMessageEmbedEventModel, DefaultListenerResult> {
}

View File

@@ -1,9 +0,0 @@
package dev.sheldan.abstracto.core.listener.sync.jda;
import dev.sheldan.abstracto.core.Prioritized;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.FeatureAwareListener;
import dev.sheldan.abstracto.core.models.listener.GuildMessageEmbedEventModel;
public interface MessageEmbeddedListener extends FeatureAwareListener<GuildMessageEmbedEventModel, DefaultListenerResult>, Prioritized {
}

View File

@@ -1,21 +0,0 @@
package dev.sheldan.abstracto.core.models.listener;
import dev.sheldan.abstracto.core.listener.FeatureAwareListenerModel;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.MessageEmbed;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@Builder
public class GuildMessageEmbedEventModel implements FeatureAwareListenerModel {
@Builder.Default
private List<MessageEmbed> embeds = new ArrayList<>();
private Long messageId;
private Long channelId;
private Long serverId;
}

View File

@@ -8,7 +8,7 @@ import net.dv8tion.jda.api.interactions.InteractionHook;
public class ContextUtils {
public static boolean isGuildKnown(Interaction interaction) {
return interaction.hasFullGuild();
return interaction.isFromAttachedGuild();
}
public static boolean isGuildNotKnown(Interaction interaction) {
@@ -25,7 +25,7 @@ public class ContextUtils {
}
public static boolean isUserCommand(Interaction interaction) {
return interaction.getIntegrationOwners().getUserIntegration() != null && interaction.getIntegrationOwners().getGuildIntegration() == null;
return interaction.getIntegrationOwners().isUserIntegration();
}
public static boolean isNotUserCommand(Interaction interaction) {