diff --git a/abstracto-application/abstracto-modules/anti-raid/anti-raid-impl/pom.xml b/abstracto-application/abstracto-modules/anti-raid/anti-raid-impl/pom.xml index b7b7b287f..3b06c7ae8 100644 --- a/abstracto-application/abstracto-modules/anti-raid/anti-raid-impl/pom.xml +++ b/abstracto-application/abstracto-modules/anti-raid/anti-raid-impl/pom.xml @@ -3,7 +3,7 @@ anti-raid dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/anti-raid/anti-raid-int/pom.xml b/abstracto-application/abstracto-modules/anti-raid/anti-raid-int/pom.xml index 808382c47..52a375795 100644 --- a/abstracto-application/abstracto-modules/anti-raid/anti-raid-int/pom.xml +++ b/abstracto-application/abstracto-modules/anti-raid/anti-raid-int/pom.xml @@ -3,7 +3,7 @@ anti-raid dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/anti-raid/pom.xml b/abstracto-application/abstracto-modules/anti-raid/pom.xml index 9271de7d2..c2f423efc 100644 --- a/abstracto-application/abstracto-modules/anti-raid/pom.xml +++ b/abstracto-application/abstracto-modules/anti-raid/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/pom.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/pom.xml index 9f54dd3cb..0df40ed76 100644 --- a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/pom.xml +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules assignable-roles - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignableRoleButtonClickedListener.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignableRoleButtonClickedListener.java index 42e9cb780..11d38f043 100644 --- a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignableRoleButtonClickedListener.java +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/listener/AssignableRoleButtonClickedListener.java @@ -31,8 +31,8 @@ import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; -import net.dv8tion.jda.api.events.interaction.ButtonClickEvent; -import net.dv8tion.jda.api.interactions.components.ButtonInteraction; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonInteraction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -74,7 +74,7 @@ public class AssignableRoleButtonClickedListener implements ButtonClickedListene @Override public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) { - ButtonClickEvent event = model.getEvent(); + ButtonInteractionEvent event = model.getEvent(); Member member = event.getMember(); if(event.getGuild() != null && member != null) { AssignableRolePlacePayload payload = (AssignableRolePlacePayload) model.getDeserializedPayload(); @@ -219,7 +219,7 @@ public class AssignableRoleButtonClickedListener implements ButtonClickedListene @Override public Boolean handlesEvent(ButtonClickedListenerModel model) { - return AssignableRolePlaceServiceBean.ASSIGNABLE_ROLE_COMPONENT_ORIGIN.equals(model.getOrigin()); + return AssignableRolePlaceServiceBean.ASSIGNABLE_ROLE_COMPONENT_ORIGIN.equals(model.getOrigin()) && model.getEvent().isFromGuild(); } @Override diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceServiceBean.java b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceServiceBean.java index 5eb6ce592..81cbfd739 100644 --- a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceServiceBean.java +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-impl/src/main/java/dev/sheldan/abstracto/assignableroles/service/AssignableRolePlaceServiceBean.java @@ -24,7 +24,7 @@ import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.service.TemplateService; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.*; -import net.dv8tion.jda.api.interactions.components.ButtonStyle; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import org.apache.commons.lang3.BooleanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -118,9 +118,9 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic throw new EmoteNotUsableException(fakeEmote.getEmote()); } } - Optional channelOptional = channelService.getTextChannelFromServerOptional(server.getId(), assignableRolePlace.getChannel().getId()); + Optional channelOptional = channelService.getMessageChannelFromServerOptional(server.getId(), assignableRolePlace.getChannel().getId()); if (channelOptional.isPresent()) { - TextChannel textChannel = channelOptional.get(); + GuildMessageChannel textChannel = channelOptional.get(); String buttonId = componentService.generateComponentId(); String emoteMarkdown = fakeEmote != null ? fakeEmote.getEmoteRepr() : null; if (assignableRolePlace.getMessageId() != null) { @@ -223,7 +223,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic AssignablePostMessage model = prepareAssignablePostMessageModel(place); MessageToSend messageToSend = templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model, place.getServer().getId()); Long channelId = place.getChannel().getId(); - Optional channelOptional = channelService.getTextChannelFromServerOptional(place.getServer().getId(), channelId); + Optional channelOptional = channelService.getMessageChannelFromServerOptional(place.getServer().getId(), channelId); if (channelOptional.isPresent()) { log.info("Refreshing text for assignable role place {} in channel {} in post {}.", place.getId(), channelId, place.getMessageId()); return channelService.editEmbedMessageInAChannel(messageToSend.getEmbeds().get(0), channelOptional.get(), place.getMessageId()).thenCompose(message -> CompletableFuture.completedFuture(null)); @@ -435,7 +435,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic .build(); } - private CompletableFuture sendAssignablePostMessage(AssignableRolePlace place, TextChannel channel) { + private CompletableFuture sendAssignablePostMessage(AssignableRolePlace place, GuildMessageChannel channel) { AssignablePostMessage model = prepareAssignablePostMessageModel(place); MessageToSend messageToSend = templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model, place.getServer().getId()); log.info("Sending message for assignable role place {}.", place.getId()); @@ -501,9 +501,9 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic @Transactional public CompletableFuture createAssignableRolePlacePost(Long serverId, Long assignablePlaceId) { AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByPlaceId(assignablePlaceId); - Optional channelOptional = channelService.getTextChannelFromServerOptional(serverId, assignableRolePlace.getChannel().getId()); + Optional channelOptional = channelService.getMessageChannelFromServerOptional(serverId, assignableRolePlace.getChannel().getId()); if (channelOptional.isPresent()) { - TextChannel channel = channelOptional.get(); + GuildMessageChannel channel = channelOptional.get(); log.info("Sending assignable role place posts for place {} in channel {} in server {}.", assignableRolePlace.getId(), channel.getId(), serverId); return sendAssignablePostMessage(assignableRolePlace, channel); } else { diff --git a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/pom.xml b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/pom.xml index 5e0e4338a..cd448fb39 100644 --- a/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/pom.xml +++ b/abstracto-application/abstracto-modules/assignable-roles/assignable-roles-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules assignable-roles - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 assignable-roles-int diff --git a/abstracto-application/abstracto-modules/assignable-roles/pom.xml b/abstracto-application/abstracto-modules/assignable-roles/pom.xml index 161ba7dbf..4aa2a0160 100644 --- a/abstracto-application/abstracto-modules/assignable-roles/pom.xml +++ b/abstracto-application/abstracto-modules/assignable-roles/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules abstracto-modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/dynamic-activity/dynamic-activity-impl/pom.xml b/abstracto-application/abstracto-modules/dynamic-activity/dynamic-activity-impl/pom.xml index eef963953..d5fa83702 100644 --- a/abstracto-application/abstracto-modules/dynamic-activity/dynamic-activity-impl/pom.xml +++ b/abstracto-application/abstracto-modules/dynamic-activity/dynamic-activity-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules dynamic-activity - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/dynamic-activity/dynamic-activity-int/pom.xml b/abstracto-application/abstracto-modules/dynamic-activity/dynamic-activity-int/pom.xml index 88f53c337..538658dee 100644 --- a/abstracto-application/abstracto-modules/dynamic-activity/dynamic-activity-int/pom.xml +++ b/abstracto-application/abstracto-modules/dynamic-activity/dynamic-activity-int/pom.xml @@ -3,7 +3,7 @@ dynamic-activity dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/dynamic-activity/pom.xml b/abstracto-application/abstracto-modules/dynamic-activity/pom.xml index 6c81499de..767c97078 100644 --- a/abstracto-application/abstracto-modules/dynamic-activity/pom.xml +++ b/abstracto-application/abstracto-modules/dynamic-activity/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/pom.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/pom.xml index 2305c2686..b8e42c944 100644 --- a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/pom.xml +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/pom.xml @@ -3,7 +3,7 @@ entertainment dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/pom.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-int/pom.xml index be272dd03..5c59644dc 100644 --- a/abstracto-application/abstracto-modules/entertainment/entertainment-int/pom.xml +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/pom.xml @@ -3,7 +3,7 @@ entertainment dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/entertainment/pom.xml b/abstracto-application/abstracto-modules/entertainment/pom.xml index 8a88f2c6b..ed6608a6a 100644 --- a/abstracto-application/abstracto-modules/entertainment/pom.xml +++ b/abstracto-application/abstracto-modules/entertainment/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/pom.xml b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/pom.xml index 509e908ac..f7f4931ec 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/pom.xml +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules experience-tracking - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/pom.xml b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/pom.xml index 099fa4ea4..8476cf29a 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/pom.xml +++ b/abstracto-application/abstracto-modules/experience-tracking/experience-tracking-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules experience-tracking - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/experience-tracking/pom.xml b/abstracto-application/abstracto-modules/experience-tracking/pom.xml index b8e330d89..cc33aea73 100644 --- a/abstracto-application/abstracto-modules/experience-tracking/pom.xml +++ b/abstracto-application/abstracto-modules/experience-tracking/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules abstracto-modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/invite-filter/invite-filter-impl/pom.xml b/abstracto-application/abstracto-modules/invite-filter/invite-filter-impl/pom.xml index 9b294d762..818fed729 100644 --- a/abstracto-application/abstracto-modules/invite-filter/invite-filter-impl/pom.xml +++ b/abstracto-application/abstracto-modules/invite-filter/invite-filter-impl/pom.xml @@ -3,7 +3,7 @@ invite-filter dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/invite-filter/invite-filter-int/pom.xml b/abstracto-application/abstracto-modules/invite-filter/invite-filter-int/pom.xml index 0045d5f14..c5212eadd 100644 --- a/abstracto-application/abstracto-modules/invite-filter/invite-filter-int/pom.xml +++ b/abstracto-application/abstracto-modules/invite-filter/invite-filter-int/pom.xml @@ -3,7 +3,7 @@ invite-filter dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/invite-filter/pom.xml b/abstracto-application/abstracto-modules/invite-filter/pom.xml index f063ded55..b2aea699c 100644 --- a/abstracto-application/abstracto-modules/invite-filter/pom.xml +++ b/abstracto-application/abstracto-modules/invite-filter/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/pom.xml b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/pom.xml index 25ceb6dd5..883868084 100644 --- a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/pom.xml +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/pom.xml @@ -3,7 +3,7 @@ link-embed dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedDeleteButtonClickedListener.java b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedDeleteButtonClickedListener.java index dc3d159ec..423394564 100644 --- a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedDeleteButtonClickedListener.java +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedDeleteButtonClickedListener.java @@ -16,7 +16,7 @@ import dev.sheldan.abstracto.linkembed.service.MessageEmbedMetricService; import dev.sheldan.abstracto.linkembed.service.MessageEmbedServiceBean; import dev.sheldan.abstracto.linkembed.service.management.MessageEmbedPostManagementService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.interaction.ButtonClickEvent; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -51,7 +51,7 @@ public class MessageEmbedDeleteButtonClickedListener implements ButtonClickedLis @Override public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) { - ButtonClickEvent event = model.getEvent(); + ButtonInteractionEvent event = model.getEvent(); MessageEmbedDeleteButtonPayload payload = (MessageEmbedDeleteButtonPayload) model.getDeserializedPayload(); Long clickingUserId = event.getInteraction().getUser().getIdLong(); boolean embeddedUserRemoves = clickingUserId.equals(payload.getEmbeddedUserId()); @@ -77,7 +77,7 @@ public class MessageEmbedDeleteButtonClickedListener implements ButtonClickedLis @Override public Boolean handlesEvent(ButtonClickedListenerModel model) { - return MessageEmbedServiceBean.MESSAGE_EMBED_DELETE_ORIGIN.equals(model.getOrigin()); + return MessageEmbedServiceBean.MESSAGE_EMBED_DELETE_ORIGIN.equals(model.getOrigin()) && model.getEvent().isFromGuild(); } @Override diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedListener.java b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedListener.java index 38b21aaeb..4510f9430 100644 --- a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedListener.java +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedListener.java @@ -7,6 +7,7 @@ import dev.sheldan.abstracto.core.listener.sync.jda.MessageReceivedListener; import dev.sheldan.abstracto.core.metric.service.CounterMetric; import dev.sheldan.abstracto.core.metric.service.MetricService; import dev.sheldan.abstracto.core.metric.service.MetricTag; +import dev.sheldan.abstracto.core.models.GuildMemberMessageChannel; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; import dev.sheldan.abstracto.core.service.MessageCache; @@ -97,9 +98,16 @@ public class MessageEmbedListener implements MessageReceivedListener { @Transactional public void embedSingleLink(Message message, Long cause, CachedMessage cachedMessage) { + GuildMemberMessageChannel context = GuildMemberMessageChannel + .builder() + .guildChannel(message.getGuildChannel()) + .member(message.getMember()) + .guild(message.getGuild()) + .message(message) + .build(); log.info("Embedding link to message {} in channel {} in server {} to channel {} and server {}.", cachedMessage.getMessageId(), cachedMessage.getChannelId(), cachedMessage.getServerId(), message.getChannel().getId(), message.getGuild().getId()); - messageEmbedService.embedLink(cachedMessage, message.getTextChannel(), cause , message).thenAccept(unused -> + messageEmbedService.embedLink(cachedMessage, message.getGuildChannel(), cause , context).thenAccept(unused -> metricService.incrementCounter(MESSAGE_EMBED_CREATED) ).exceptionally(throwable -> { log.error("Failed to embed link towards message {} in channel {} in sever {} linked from message {} in channel {} in server {}.", cachedMessage.getMessageId(), cachedMessage.getChannelId(), cachedMessage.getServerId(), diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/interaction/MessageEmbedContextCommandListener.java b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/interaction/MessageEmbedContextCommandListener.java new file mode 100644 index 000000000..76a2adf8c --- /dev/null +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/listener/interaction/MessageEmbedContextCommandListener.java @@ -0,0 +1,83 @@ +package dev.sheldan.abstracto.linkembed.listener.interaction; + +import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.interaction.MessageContextConfig; +import dev.sheldan.abstracto.core.listener.DefaultListenerResult; +import dev.sheldan.abstracto.core.listener.async.MessageContextCommandListener; +import dev.sheldan.abstracto.core.models.GuildMemberMessageChannel; +import dev.sheldan.abstracto.core.models.cache.CachedMessage; +import dev.sheldan.abstracto.core.models.listener.interaction.MessageContextInteractionModel; +import dev.sheldan.abstracto.core.service.MessageCache; +import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; +import dev.sheldan.abstracto.linkembed.config.LinkEmbedFeatureDefinition; +import dev.sheldan.abstracto.linkembed.service.MessageEmbedService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; +import net.dv8tion.jda.api.interactions.commands.Command; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@Slf4j +public class MessageEmbedContextCommandListener implements MessageContextCommandListener { + + @Autowired + private MessageCache messageCache; + + @Autowired + private MessageEmbedService messageEmbedService; + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Autowired + private MessageEmbedContextCommandListener self; + + @Override + public DefaultListenerResult execute(MessageContextInteractionModel model) { + MessageContextInteractionEvent event = model.getEvent(); + event.deferReply().queue(); + Message targetMessage = event.getInteraction().getTarget(); + Member actor = model.getEvent().getMember(); + + messageCache.getMessageFromCache(targetMessage) + .thenAccept(cachedMessage -> self.embedMessage(model, actor, cachedMessage)); + return DefaultListenerResult.PROCESSED; + } + + @Transactional + public void embedMessage(MessageContextInteractionModel model, Member actor, CachedMessage cachedMessage) { + Long userEmbeddingUserInServerId = userInServerManagementService.loadOrCreateUser(actor).getUserInServerId(); + GuildMemberMessageChannel context = GuildMemberMessageChannel + .builder() + .message(null) + .guild(actor.getGuild()) + .member(actor) + .guildChannel(model.getEvent().getGuildChannel()) + .build(); + messageEmbedService.embedLink(cachedMessage, model.getEvent().getGuildChannel(), userEmbeddingUserInServerId, context, model.getEvent().getInteraction()); + } + + @Override + public FeatureDefinition getFeature() { + return LinkEmbedFeatureDefinition.LINK_EMBEDS; + } + + @Override + public MessageContextConfig getConfig() { + return MessageContextConfig + .builder() + .name("Embed message") + .build(); + } + + @Override + public Boolean handlesEvent(MessageContextInteractionModel model) { + return model.getEvent().getName().equals(getConfig().getName()) + && model.getEvent().isFromGuild() + && model.getEvent().getCommandType().equals(Command.Type.MESSAGE); + } +} diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedServiceBean.java b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedServiceBean.java index e5beae121..679c972ab 100644 --- a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedServiceBean.java +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/main/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedServiceBean.java @@ -1,5 +1,7 @@ package dev.sheldan.abstracto.linkembed.service; +import dev.sheldan.abstracto.core.interaction.InteractionService; +import dev.sheldan.abstracto.core.models.GuildMemberMessageChannel; import dev.sheldan.abstracto.core.models.ServerChannelMessage; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.database.AServer; @@ -22,9 +24,11 @@ import dev.sheldan.abstracto.linkembed.model.MessageEmbedLink; import dev.sheldan.abstracto.linkembed.model.database.EmbeddedMessage; import dev.sheldan.abstracto.linkembed.service.management.MessageEmbedPostManagementService; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.interactions.commands.CommandInteraction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -48,18 +52,12 @@ public class MessageEmbedServiceBean implements MessageEmbedService { public static final String MESSAGE_EMBED_TEMPLATE = "message_embed"; public static final String REMOVAL_EMOTE = "removeEmbed"; - @Autowired - private ChannelManagementService channelManagementService; - @Autowired private ServerManagementService serverManagementService; @Autowired private UserInServerManagementService userInServerManagementService; - @Autowired - private MemberService memberService; - @Autowired private UserService userService; @@ -84,15 +82,15 @@ public class MessageEmbedServiceBean implements MessageEmbedService { @Autowired private MessageService messageService; - @Autowired - private EmoteService emoteService; - @Autowired private ComponentService componentServiceBean; @Autowired private FeatureModeService featureModeService; + @Autowired + private InteractionService interactionService; + @Autowired private ComponentPayloadManagementService componentPayloadManagementService; @@ -126,10 +124,10 @@ public class MessageEmbedServiceBean implements MessageEmbedService { } @Override - public void embedLinks(List linksToEmbed, TextChannel target, Long userEmbeddingUserInServerId, Message embeddingMessage) { + public void embedLinks(List linksToEmbed, GuildMessageChannel target, Long userEmbeddingUserInServerId, GuildMemberMessageChannel executionContext) { linksToEmbed.forEach(messageEmbedLink -> messageCache.getMessageFromCache(messageEmbedLink.getServerId(), messageEmbedLink.getChannelId(), messageEmbedLink.getMessageId()) - .thenAccept(cachedMessage -> self.embedLink(cachedMessage, target, userEmbeddingUserInServerId, embeddingMessage) + .thenAccept(cachedMessage -> self.embedLink(cachedMessage, target, userEmbeddingUserInServerId, executionContext) ).exceptionally(throwable -> { log.error("Message embedding from cache failed for message {}.", messageEmbedLink.getMessageId(), throwable); return null; @@ -139,13 +137,21 @@ public class MessageEmbedServiceBean implements MessageEmbedService { @Override @Transactional - public CompletableFuture embedLink(CachedMessage cachedMessage, TextChannel target, Long userEmbeddingUserInServerId, Message embeddingMessage) { + public CompletableFuture embedLink(CachedMessage cachedMessage, GuildMessageChannel target, Long userEmbeddingUserInServerId, GuildMemberMessageChannel executionContext) { boolean deletionButtonEnabled = featureModeService.featureModeActive(LinkEmbedFeatureDefinition.LINK_EMBEDS, target.getGuild(), LinkEmbedFeatureMode.DELETE_BUTTON); - return buildTemplateParameter(embeddingMessage, cachedMessage, deletionButtonEnabled).thenCompose(messageEmbeddedModel -> + return buildTemplateParameter(executionContext, cachedMessage, deletionButtonEnabled).thenCompose(messageEmbeddedModel -> self.sendEmbeddingMessage(cachedMessage, target, userEmbeddingUserInServerId, messageEmbeddedModel, deletionButtonEnabled) ); } + @Override + public CompletableFuture embedLink(CachedMessage cachedMessage, GuildMessageChannel target, Long userEmbeddingUserInServerId, GuildMemberMessageChannel executionContext, CommandInteraction interaction) { + boolean deletionButtonEnabled = featureModeService.featureModeActive(LinkEmbedFeatureDefinition.LINK_EMBEDS, target.getGuild(), LinkEmbedFeatureMode.DELETE_BUTTON); + return buildTemplateParameter(executionContext, cachedMessage, deletionButtonEnabled).thenCompose(messageEmbeddedModel -> + self.sendEmbeddingMessageToInteraction(cachedMessage, target, userEmbeddingUserInServerId, messageEmbeddedModel, deletionButtonEnabled, interaction) + ); + } + @Override public CompletableFuture cleanUpOldMessageEmbeds() { Instant oldestDate = Instant.now().truncatedTo(ChronoUnit.DAYS).minus(embedRemovalDays, ChronoUnit.DAYS); @@ -243,11 +249,15 @@ public class MessageEmbedServiceBean implements MessageEmbedService { } @Transactional - public CompletableFuture sendEmbeddingMessage(CachedMessage cachedMessage, TextChannel target, + public CompletableFuture sendEmbeddingMessage(CachedMessage cachedMessage, GuildMessageChannel target, Long userEmbeddingUserInServerId, MessageEmbeddedModel messageEmbeddedModel, Boolean deletionButtonEnabled) { MessageToSend embed = templateService.renderEmbedTemplate(MESSAGE_EMBED_TEMPLATE, messageEmbeddedModel, target.getGuild().getIdLong()); - AUserInAServer cause = userInServerManagementService.loadOrCreateUser(userEmbeddingUserInServerId); List> completableFutures = channelService.sendMessageToSendToChannel(embed, target); + return postProcessLinkEmbed(cachedMessage, userEmbeddingUserInServerId, messageEmbeddedModel, deletionButtonEnabled, completableFutures); + } + + private CompletableFuture postProcessLinkEmbed(CachedMessage cachedMessage, Long userEmbeddingUserInServerId, MessageEmbeddedModel messageEmbeddedModel, Boolean deletionButtonEnabled, List> completableFutures) { + AUserInAServer cause = userInServerManagementService.loadOrCreateUser(userEmbeddingUserInServerId); Long embeddingUserId = cause.getUserReference().getId(); log.debug("Embedding message {} from channel {} from server {}, because of user {}", cachedMessage.getMessageId(), cachedMessage.getChannelId(), cachedMessage.getServerId(), embeddingUserId); @@ -257,6 +267,14 @@ public class MessageEmbedServiceBean implements MessageEmbedService { }); } + @Transactional + public CompletableFuture sendEmbeddingMessageToInteraction(CachedMessage cachedMessage, GuildMessageChannel target, + Long userEmbeddingUserInServerId, MessageEmbeddedModel messageEmbeddedModel, Boolean deletionButtonEnabled, CommandInteraction interaction) { + MessageToSend embed = templateService.renderEmbedTemplate(MESSAGE_EMBED_TEMPLATE, messageEmbeddedModel, target.getGuild().getIdLong()); + List> completableFutures = interactionService.sendMessageToInteraction(embed, interaction.getHook()); + return postProcessLinkEmbed(cachedMessage, userEmbeddingUserInServerId, messageEmbeddedModel, deletionButtonEnabled, completableFutures); + } + @Transactional public CompletableFuture addDeletionPossibility(CachedMessage cachedMessage, MessageEmbeddedModel messageEmbeddedModel, Message createdMessage, Long embeddingUserId, Boolean deletionButtonEnabled) { @@ -299,34 +317,37 @@ public class MessageEmbedServiceBean implements MessageEmbedService { messageEmbedPostManagementService.createMessageEmbed(cachedMessage, createdMessage, innerCause, deletionButtonId); } - private CompletableFuture buildTemplateParameter(Message message, CachedMessage embeddedMessage, Boolean deletionButtonEnabled) { + private CompletableFuture buildTemplateParameter(GuildMemberMessageChannel executionContext, CachedMessage embeddedMessage, Boolean deletionButtonEnabled) { return userService.retrieveUserForId(embeddedMessage.getAuthor().getAuthorId()).thenApply(authorUser -> - self.loadMessageEmbedModel(message, embeddedMessage, authorUser, deletionButtonEnabled) + self.loadMessageEmbedModel(executionContext, embeddedMessage, authorUser, deletionButtonEnabled) ).exceptionally(throwable -> { log.warn("Failed to retrieve author for user {}.", embeddedMessage.getAuthor().getAuthorId(), throwable); - return self.loadMessageEmbedModel(message, embeddedMessage, null, deletionButtonEnabled); + return self.loadMessageEmbedModel(executionContext, embeddedMessage, null, deletionButtonEnabled); }); } @Transactional - public MessageEmbeddedModel loadMessageEmbedModel(Message message, CachedMessage embeddedMessage, User userAuthor, Boolean deletionButtonEnabled) { - Optional textChannelFromServer = channelService.getTextChannelFromServerOptional(embeddedMessage.getServerId(), embeddedMessage.getChannelId()); - TextChannel sourceChannel = textChannelFromServer.orElse(null); + public MessageEmbeddedModel loadMessageEmbedModel(GuildMemberMessageChannel executionContext, CachedMessage embeddedMessage, User userAuthor, Boolean deletionButtonEnabled) { + Optional textChannelFromServer = channelService.getMessageChannelFromServerOptional(embeddedMessage.getServerId(), embeddedMessage.getChannelId()); + GuildMessageChannel sourceChannel = textChannelFromServer.orElse(null); ButtonConfigModel buttonConfigModel = ButtonConfigModel .builder() .buttonId(deletionButtonEnabled ? componentServiceBean.generateComponentId() : null) .build(); - - Long referencedMessageId = message.getReferencedMessage() != null ? message.getReferencedMessage().getIdLong() : null; - Boolean shouldMentionReferencedAuthor = shouldMentionReferencedAuthor(message); + Long referencedMessageId = null; + Boolean shouldMentionReferencedAuthor = false; + if(executionContext.getMessage() != null) { + referencedMessageId = executionContext.getMessage().getReferencedMessage() != null ? executionContext.getMessage().getReferencedMessage().getIdLong() : null; + shouldMentionReferencedAuthor = shouldMentionReferencedAuthor(executionContext.getMessage()); + } return MessageEmbeddedModel .builder() - .member(message.getMember()) + .member(executionContext.getMember()) .author(userAuthor) .sourceChannel(sourceChannel) - .embeddingUser(message.getMember()) - .messageChannel(message.getChannel()) - .guild(message.getGuild()) + .embeddingUser(executionContext.getMember()) + .messageChannel(executionContext.getGuildChannel()) + .guild(executionContext.getGuild()) .useButton(deletionButtonEnabled) .embeddedMessage(embeddedMessage) .referencedMessageId(referencedMessageId) diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/test/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedListenerTest.java b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/test/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedListenerTest.java index 480ba378f..02e7d4721 100644 --- a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/test/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedListenerTest.java +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/test/java/dev/sheldan/abstracto/linkembed/listener/MessageEmbedListenerTest.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.linkembed.listener; import dev.sheldan.abstracto.core.metric.service.MetricService; +import dev.sheldan.abstracto.core.models.GuildMemberMessageChannel; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; @@ -49,11 +50,14 @@ public class MessageEmbedListenerTest { @Mock private MessageEmbedListener self; + @Mock + private GuildMemberMessageChannel context; + @Mock private Message message; @Mock - private TextChannel textChannel; + private GuildMessageChannel textChannel; @Mock private MessageReceivedModel model; @@ -71,8 +75,8 @@ public class MessageEmbedListenerTest { @Before public void setup(){ when(guild.getIdLong()).thenReturn(FIRST_SERVER_ID); - when(message.getGuild()).thenReturn(guild); - when(message.getChannel()).thenReturn(textChannel); + when(context.getGuild()).thenReturn(guild); + when(context.getGuildChannel()).thenReturn(textChannel); } @Test @@ -82,7 +86,6 @@ public class MessageEmbedListenerTest { setupMessageConfig(); List foundMessageLinks = new ArrayList<>(); when(messageEmbedService.getLinksInMessage(text)).thenReturn(foundMessageLinks); - when(model.getMessage()).thenReturn(message); testUnit.execute(model); verify(messageService, times(0)).deleteMessage(message); } @@ -124,7 +127,7 @@ public class MessageEmbedListenerTest { when(foundLink.getServerId()).thenReturn(SECOND_SERVER_ID); List foundMessageLinks = Arrays.asList(foundLink); Member author = Mockito.mock(Member.class); - when(message.getMember()).thenReturn(author); + when(context.getMember()).thenReturn(author); when(userInServerManagementService.loadOrCreateUser(author)).thenReturn(userInAServer); when(messageEmbedService.getLinksInMessage(text)).thenReturn(foundMessageLinks); when(model.getMessage()).thenReturn(message); @@ -153,8 +156,8 @@ public class MessageEmbedListenerTest { when(message.getContentRaw()).thenReturn(completeMessage); setupMessageConfig(); Member author = Mockito.mock(Member.class); - when(message.getMember()).thenReturn(author); - when(message.getGuild()).thenReturn(guild); + when(context.getMember()).thenReturn(author); + when(context.getGuild()).thenReturn(guild); when(guild.getIdLong()).thenReturn(FIRST_SERVER_ID); when(userInServerManagementService.loadOrCreateUser(author)).thenReturn(embeddingUser); CachedMessage cachedMessage = Mockito.mock(CachedMessage.class); @@ -185,7 +188,7 @@ public class MessageEmbedListenerTest { when(message.getContentRaw()).thenReturn(text); setupMessageConfig(); Member author = Mockito.mock(Member.class); - when(message.getMember()).thenReturn(author); + when(context.getMember()).thenReturn(author); when(userInServerManagementService.loadOrCreateUser(author)).thenReturn(userInAServer); CachedMessage cachedMessage = Mockito.mock(CachedMessage.class); CachedMessage secondCachedMessage = Mockito.mock(CachedMessage.class); @@ -203,8 +206,8 @@ public class MessageEmbedListenerTest { public void testLoadUserAndEmbed() { CachedMessage cachedMessage = Mockito.mock(CachedMessage.class); long userId = 3L; - when(message.getTextChannel()).thenReturn(textChannel); - when(messageEmbedService.embedLink(cachedMessage, textChannel, userId, message)).thenReturn(CompletableFuture.completedFuture(null)); + when(context.getGuildChannel()).thenReturn(textChannel); + when(messageEmbedService.embedLink(cachedMessage, textChannel, userId, context)).thenReturn(CompletableFuture.completedFuture(null)); testUnit.embedSingleLink(message, userId, cachedMessage); verify(metricService, times(1)).incrementCounter(any()); } @@ -220,7 +223,7 @@ public class MessageEmbedListenerTest { when(foundLink.getChannelId()).thenReturn(FIRST_CHANNEL_ID); List foundMessageLinks = Arrays.asList(foundLink); Member author = Mockito.mock(Member.class); - when(message.getMember()).thenReturn(author); + when(context.getMember()).thenReturn(author); when(userInServerManagementService.loadOrCreateUser(author)).thenReturn(userInAServer); CachedMessage cachedMessage = Mockito.mock(CachedMessage.class); when(messageCache.getMessageFromCache(FIRST_SERVER_ID, FIRST_CHANNEL_ID, FIRST_MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(cachedMessage)); diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/test/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedServiceBeanTest.java b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/test/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedServiceBeanTest.java index a279ff0a4..e779d94e6 100644 --- a/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/test/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-impl/src/test/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedServiceBeanTest.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.linkembed.service; +import dev.sheldan.abstracto.core.models.GuildMemberMessageChannel; import dev.sheldan.abstracto.core.models.cache.CachedAuthor; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.database.AUser; @@ -73,10 +74,13 @@ public class MessageEmbedServiceBeanTest { private FeatureModeService featureModeService; @Mock - private TextChannel textChannel; + private GuildMessageChannel textChannel; @Mock - private Message embeddingMessage; + private GuildMemberMessageChannel embeddingMessage; + + @Mock + private Message message; @Mock private Guild guild; @@ -176,7 +180,7 @@ public class MessageEmbedServiceBeanTest { when(messageCache.getMessageFromCache(SERVER_ID,channelId, firstMessageId)).thenReturn(CompletableFuture.completedFuture(firstCachedMessage)); Long embeddingUserId = 5L; testUnit.embedLinks(linksToEmbed, textChannel, embeddingUserId, embeddingMessage); - verify( self, times(1)).embedLink(eq(firstCachedMessage), eq(textChannel), eq(embeddingUserId) , eq(embeddingMessage)); + verify( self, times(1)).embedLink(firstCachedMessage, textChannel, embeddingUserId, embeddingMessage); } @Test @@ -258,17 +262,17 @@ public class MessageEmbedServiceBeanTest { @Test public void testLoadUserAndPersistMessage() { when(userInServerManagementService.loadOrCreateUser(EMBEDDING_USER_IN_SERVER_ID)).thenReturn(embeddingUser); - testUnit.loadUserAndPersistMessage(cachedMessage, EMBEDDING_USER_IN_SERVER_ID, embeddingMessage, null); - verify(messageEmbedPostManagementService, times(1)).createMessageEmbed(cachedMessage, embeddingMessage, embeddingUser, null); + testUnit.loadUserAndPersistMessage(cachedMessage, EMBEDDING_USER_IN_SERVER_ID, message, null); + verify(messageEmbedPostManagementService, times(1)).createMessageEmbed(cachedMessage, message, embeddingUser, null); } @Test public void testLoadMessageEmbedModel() { when(cachedMessage.getServerId()).thenReturn(SERVER_ID); when(cachedMessage.getChannelId()).thenReturn(CHANNEL_ID); - when(channelService.getTextChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.of(textChannel)); + when(channelService.getMessageChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.of(textChannel)); when(embeddingMessage.getGuild()).thenReturn(guild); - when(embeddingMessage.getChannel()).thenReturn(textChannel); + when(embeddingMessage.getGuildChannel()).thenReturn(textChannel); when(embeddingMessage.getMember()).thenReturn(embeddingMember); MessageEmbeddedModel createdModel = testUnit.loadMessageEmbedModel(embeddingMessage, cachedMessage, embeddedUser, false); Assert.assertEquals(textChannel, createdModel.getSourceChannel()); diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-int/pom.xml b/abstracto-application/abstracto-modules/link-embed/link-embed-int/pom.xml index 4ad059e75..5151342fc 100644 --- a/abstracto-application/abstracto-modules/link-embed/link-embed-int/pom.xml +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-int/pom.xml @@ -3,7 +3,7 @@ link-embed dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-int/src/main/java/dev/sheldan/abstracto/linkembed/model/template/MessageEmbeddedModel.java b/abstracto-application/abstracto-modules/link-embed/link-embed-int/src/main/java/dev/sheldan/abstracto/linkembed/model/template/MessageEmbeddedModel.java index 2821919ec..fabcf3a78 100644 --- a/abstracto-application/abstracto-modules/link-embed/link-embed-int/src/main/java/dev/sheldan/abstracto/linkembed/model/template/MessageEmbeddedModel.java +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-int/src/main/java/dev/sheldan/abstracto/linkembed/model/template/MessageEmbeddedModel.java @@ -6,8 +6,8 @@ import dev.sheldan.abstracto.core.models.template.button.ButtonConfigModel; import lombok.Getter; import lombok.Setter; import lombok.experimental.SuperBuilder; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.User; @Getter @@ -16,7 +16,7 @@ import net.dv8tion.jda.api.entities.User; public class MessageEmbeddedModel extends UserInitiatedServerContext { private CachedMessage embeddedMessage; private User author; - private TextChannel sourceChannel; + private GuildMessageChannel sourceChannel; private Member embeddingUser; private ButtonConfigModel buttonConfigModel; private Long referencedMessageId; diff --git a/abstracto-application/abstracto-modules/link-embed/link-embed-int/src/main/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedService.java b/abstracto-application/abstracto-modules/link-embed/link-embed-int/src/main/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedService.java index 6eb6bbcc4..3760bd613 100644 --- a/abstracto-application/abstracto-modules/link-embed/link-embed-int/src/main/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedService.java +++ b/abstracto-application/abstracto-modules/link-embed/link-embed-int/src/main/java/dev/sheldan/abstracto/linkembed/service/MessageEmbedService.java @@ -1,16 +1,18 @@ package dev.sheldan.abstracto.linkembed.service; +import dev.sheldan.abstracto.core.models.GuildMemberMessageChannel; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.linkembed.model.MessageEmbedLink; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.GuildMessageChannel; +import net.dv8tion.jda.api.interactions.commands.CommandInteraction; import java.util.List; import java.util.concurrent.CompletableFuture; public interface MessageEmbedService { List getLinksInMessage(String message); - void embedLinks(List linksToEmbed, TextChannel target, Long userEmbeddingUserInServerId, Message embeddingMessage); - CompletableFuture embedLink(CachedMessage cachedMessage, TextChannel target, Long userEmbeddingUserInServerId, Message embeddingMessage); + void embedLinks(List linksToEmbed, GuildMessageChannel target, Long userEmbeddingUserInServerId, GuildMemberMessageChannel executionContext); + CompletableFuture embedLink(CachedMessage cachedMessage, GuildMessageChannel target, Long userEmbeddingUserInServerId, GuildMemberMessageChannel executionContext); + CompletableFuture embedLink(CachedMessage cachedMessage, GuildMessageChannel target, Long userEmbeddingUserInServerId, GuildMemberMessageChannel executionContext, CommandInteraction interaction); CompletableFuture cleanUpOldMessageEmbeds(); } diff --git a/abstracto-application/abstracto-modules/link-embed/pom.xml b/abstracto-application/abstracto-modules/link-embed/pom.xml index 07a93f56b..fc4eec15d 100644 --- a/abstracto-application/abstracto-modules/link-embed/pom.xml +++ b/abstracto-application/abstracto-modules/link-embed/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/logging/logging-impl/pom.xml b/abstracto-application/abstracto-modules/logging/logging-impl/pom.xml index 4fbbd5223..6a0bcb14a 100644 --- a/abstracto-application/abstracto-modules/logging/logging-impl/pom.xml +++ b/abstracto-application/abstracto-modules/logging/logging-impl/pom.xml @@ -3,7 +3,7 @@ logging dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/logging/logging-impl/src/main/java/dev/sheldan/abstracto/logging/listener/MessageDeleteLogListener.java b/abstracto-application/abstracto-modules/logging/logging-impl/src/main/java/dev/sheldan/abstracto/logging/listener/MessageDeleteLogListener.java index 9fdc01a8c..faf62cc7b 100644 --- a/abstracto-application/abstracto-modules/logging/logging-impl/src/main/java/dev/sheldan/abstracto/logging/listener/MessageDeleteLogListener.java +++ b/abstracto-application/abstracto-modules/logging/logging-impl/src/main/java/dev/sheldan/abstracto/logging/listener/MessageDeleteLogListener.java @@ -20,6 +20,7 @@ import dev.sheldan.abstracto.logging.config.LoggingPostTarget; import dev.sheldan.abstracto.logging.model.template.MessageDeletedAttachmentLog; import dev.sheldan.abstracto.logging.model.template.MessageDeletedLog; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.TextChannel; import org.springframework.beans.factory.annotation.Autowired; @@ -76,7 +77,7 @@ public class MessageDeleteLogListener implements AsyncMessageDeletedListener { public void executeListener(CachedMessage messageFromCache, Member authorMember) { log.debug("Message {} in channel {} in guild {} was deleted.", messageFromCache.getMessageId(), messageFromCache.getChannelId(), messageFromCache.getServerId()); - TextChannel textChannel = channelService.getTextChannelFromServer(messageFromCache.getServerId(), messageFromCache.getChannelId()); + GuildMessageChannel textChannel = channelService.getMessageChannelFromServer(messageFromCache.getServerId(), messageFromCache.getChannelId()); MessageDeletedLog logModel = MessageDeletedLog .builder() .cachedMessage(messageFromCache) diff --git a/abstracto-application/abstracto-modules/logging/logging-impl/src/main/java/dev/sheldan/abstracto/logging/listener/MessageEditedListener.java b/abstracto-application/abstracto-modules/logging/logging-impl/src/main/java/dev/sheldan/abstracto/logging/listener/MessageEditedListener.java index e518ed0c7..92a345a94 100644 --- a/abstracto-application/abstracto-modules/logging/logging-impl/src/main/java/dev/sheldan/abstracto/logging/listener/MessageEditedListener.java +++ b/abstracto-application/abstracto-modules/logging/logging-impl/src/main/java/dev/sheldan/abstracto/logging/listener/MessageEditedListener.java @@ -17,6 +17,7 @@ import dev.sheldan.abstracto.logging.config.LoggingPostTarget; import dev.sheldan.abstracto.logging.model.template.MessageDeletedAttachmentLog; import dev.sheldan.abstracto.logging.model.template.MessageEditedLog; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import org.springframework.beans.factory.annotation.Autowired; @@ -56,7 +57,7 @@ public class MessageEditedListener implements AsyncMessageUpdatedListener { return DefaultListenerResult.IGNORED; } log.debug("Message {} in channel {} in guild {} was edited.", messageBefore.getMessageId(), messageBefore.getChannelId(), model.getServerId()); - TextChannel textChannel = channelService.getTextChannelFromServer(model.getServerId(), messageBefore.getChannelId()); + GuildMessageChannel textChannel = channelService.getMessageChannelFromServer(model.getServerId(), messageBefore.getChannelId()); MessageEditedLog lodModel = MessageEditedLog .builder() .messageAfter(messageAfter) diff --git a/abstracto-application/abstracto-modules/logging/logging-impl/src/test/java/dev/sheldan/abstracto/logging/listener/MessageDeleteLogListenerTest.java b/abstracto-application/abstracto-modules/logging/logging-impl/src/test/java/dev/sheldan/abstracto/logging/listener/MessageDeleteLogListenerTest.java index 0117e30ec..12c729493 100644 --- a/abstracto-application/abstracto-modules/logging/logging-impl/src/test/java/dev/sheldan/abstracto/logging/listener/MessageDeleteLogListenerTest.java +++ b/abstracto-application/abstracto-modules/logging/logging-impl/src/test/java/dev/sheldan/abstracto/logging/listener/MessageDeleteLogListenerTest.java @@ -108,7 +108,7 @@ public class MessageDeleteLogListenerTest { MessageToSend messageToSend = Mockito.mock(MessageToSend.class); when(member.getGuild()).thenReturn(guild); when(templateService.renderEmbedTemplate(eq(MessageDeleteLogListener.MESSAGE_DELETED_TEMPLATE), captor.capture(), eq(SERVER_ID))).thenReturn(messageToSend); - when(channelService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel); + when(channelService.getMessageChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel); testUnit.executeListener(deletedMessage, member); verify(postTargetService, times(1)).sendEmbedInPostTarget(messageToSend, LoggingPostTarget.DELETE_LOG, SERVER_ID); MessageDeletedLog messageDeletedLog = captor.getValue(); @@ -123,7 +123,7 @@ public class MessageDeleteLogListenerTest { String attachmentUrl = "url"; when(deletedMessage.getServerId()).thenReturn(SERVER_ID); when(deletedMessage.getChannelId()).thenReturn(CHANNEL_ID); - when(channelService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel); + when(channelService.getMessageChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel); CachedAttachment cachedAttachment = Mockito.mock(CachedAttachment.class); when(cachedAttachment.getProxyUrl()).thenReturn(attachmentUrl); List attachmentList = Arrays.asList(cachedAttachment); @@ -147,7 +147,7 @@ public class MessageDeleteLogListenerTest { public void testExecuteListenerWithTwoAttachment() { when(deletedMessage.getServerId()).thenReturn(SERVER_ID); when(deletedMessage.getChannelId()).thenReturn(CHANNEL_ID); - when(channelService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel); + when(channelService.getMessageChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel); String attachmentUrl = "url"; String secondAttachmentUrl = "url2"; CachedAttachment cachedAttachment = Mockito.mock(CachedAttachment.class); diff --git a/abstracto-application/abstracto-modules/logging/logging-impl/src/test/java/dev/sheldan/abstracto/logging/listener/MessageEditedListenerTest.java b/abstracto-application/abstracto-modules/logging/logging-impl/src/test/java/dev/sheldan/abstracto/logging/listener/MessageEditedListenerTest.java index 1f280bce8..8356f5461 100644 --- a/abstracto-application/abstracto-modules/logging/logging-impl/src/test/java/dev/sheldan/abstracto/logging/listener/MessageEditedListenerTest.java +++ b/abstracto-application/abstracto-modules/logging/logging-impl/src/test/java/dev/sheldan/abstracto/logging/listener/MessageEditedListenerTest.java @@ -79,7 +79,7 @@ public class MessageEditedListenerTest { MessageToSend messageToSend = Mockito.mock(MessageToSend.class); ArgumentCaptor captor = ArgumentCaptor.forClass(MessageEditedLog.class); when(templateService.renderEmbedTemplate(eq(MessageEditedListener.MESSAGE_EDITED_TEMPLATE), captor.capture(), eq(SERVER_ID))).thenReturn(messageToSend); - when(channelService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(channel); + when(channelService.getMessageChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(channel); when(model.getAfter()).thenReturn(messageAfter); when(model.getBefore()).thenReturn(messageBefore); when(messageAfter.getMember()).thenReturn(author); diff --git a/abstracto-application/abstracto-modules/logging/logging-int/pom.xml b/abstracto-application/abstracto-modules/logging/logging-int/pom.xml index 9a2085482..8269ac97a 100644 --- a/abstracto-application/abstracto-modules/logging/logging-int/pom.xml +++ b/abstracto-application/abstracto-modules/logging/logging-int/pom.xml @@ -3,7 +3,7 @@ logging dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/logging/logging-int/src/main/java/dev/sheldan/abstracto/logging/model/template/MessageDeletedAttachmentLog.java b/abstracto-application/abstracto-modules/logging/logging-int/src/main/java/dev/sheldan/abstracto/logging/model/template/MessageDeletedAttachmentLog.java index 608a92a3d..5059fd02e 100644 --- a/abstracto-application/abstracto-modules/logging/logging-int/src/main/java/dev/sheldan/abstracto/logging/model/template/MessageDeletedAttachmentLog.java +++ b/abstracto-application/abstracto-modules/logging/logging-int/src/main/java/dev/sheldan/abstracto/logging/model/template/MessageDeletedAttachmentLog.java @@ -1,7 +1,9 @@ package dev.sheldan.abstracto.logging.model.template; import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import lombok.experimental.SuperBuilder; @@ -12,6 +14,8 @@ import lombok.experimental.SuperBuilder; @Getter @Setter @SuperBuilder +@AllArgsConstructor +@NoArgsConstructor public class MessageDeletedAttachmentLog extends SlimUserInitiatedServerContext { /** * The proxy URL to the attachment which was deleted. diff --git a/abstracto-application/abstracto-modules/logging/logging-int/src/main/java/dev/sheldan/abstracto/logging/model/template/MessageDeletedLog.java b/abstracto-application/abstracto-modules/logging/logging-int/src/main/java/dev/sheldan/abstracto/logging/model/template/MessageDeletedLog.java index cce7c46cb..0d2e32bc4 100644 --- a/abstracto-application/abstracto-modules/logging/logging-int/src/main/java/dev/sheldan/abstracto/logging/model/template/MessageDeletedLog.java +++ b/abstracto-application/abstracto-modules/logging/logging-int/src/main/java/dev/sheldan/abstracto/logging/model/template/MessageDeletedLog.java @@ -2,7 +2,9 @@ package dev.sheldan.abstracto.logging.model.template; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext; +import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import lombok.experimental.SuperBuilder; @@ -12,6 +14,8 @@ import lombok.experimental.SuperBuilder; @Getter @Setter @SuperBuilder +@AllArgsConstructor +@NoArgsConstructor public class MessageDeletedLog extends SlimUserInitiatedServerContext { /** * A {@link CachedMessage} representing the deleted message diff --git a/abstracto-application/abstracto-modules/logging/pom.xml b/abstracto-application/abstracto-modules/logging/pom.xml index 43c7db8e3..b7c0b32dd 100644 --- a/abstracto-application/abstracto-modules/logging/pom.xml +++ b/abstracto-application/abstracto-modules/logging/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/pom.xml b/abstracto-application/abstracto-modules/moderation/moderation-impl/pom.xml index a8f2b46ac..415e4e8de 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/pom.xml +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules moderation - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/command/SlowMode.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/command/SlowMode.java index 016e78bcb..5d2d8fefb 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/command/SlowMode.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/command/SlowMode.java @@ -43,7 +43,11 @@ public class SlowMode extends AbstractConditionableCommand { throw new EntityGuildMismatchException(); } } else { - channel = commandContext.getChannel(); + if(commandContext.getChannel() instanceof TextChannel) { + channel = (TextChannel) commandContext.getChannel(); + } else { + throw new IllegalArgumentException("Not a text channel."); + } } return slowModeService.setSlowMode(channel, duration) .thenApply(aVoid -> CommandResult.fromSuccess()); diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/MuteServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/MuteServiceBean.java index b06563c96..873ec4a54 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/MuteServiceBean.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/MuteServiceBean.java @@ -28,10 +28,7 @@ import dev.sheldan.abstracto.scheduling.service.SchedulerService; import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.service.TemplateService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @@ -159,7 +156,7 @@ public class MuteServiceBean implements MuteService { String muteNotificationMessage = templateService.renderTemplate(MUTE_NOTIFICATION_TEMPLATE, muteNotification, message.getServerId()); CompletableFuture messageCompletableFuture = messageService.sendMessageToUser(memberBeingMuted.getUser(), muteNotificationMessage); messageCompletableFuture.exceptionally(throwable -> { - TextChannel feedBackChannel = channelService.getTextChannelFromServer(message.getServerId(), message.getChannelId()); + GuildMessageChannel feedBackChannel = channelService.getMessageChannelFromServer(message.getServerId(), message.getChannelId()); channelService.sendTextToChannel(throwable.getMessage(), feedBackChannel).whenComplete((exceptionMessage, innerThrowable) -> { notificationFuture.complete(null); log.info("Successfully notified user {} in server {} about mute.", memberBeingMuted.getId(), memberBeingMuted.getGuild().getId()); diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBean.java index 633c1aef1..097089a5b 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBean.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBean.java @@ -9,10 +9,7 @@ import dev.sheldan.abstracto.moderation.model.template.command.PurgeStatusUpdate import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.service.TemplateService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.MessageHistory; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.utils.MiscUtil; import net.dv8tion.jda.api.utils.TimeUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -51,11 +48,11 @@ public class PurgeServiceBean implements PurgeService { .build(); @Override - public CompletableFuture purgeMessagesInChannel(Integer amountToDelete, TextChannel channel, Long startId, Member purgedMember) { + public CompletableFuture purgeMessagesInChannel(Integer amountToDelete, GuildMessageChannel channel, Long startId, Member purgedMember) { return purgeMessages(amountToDelete, channel, startId, purgedMember, amountToDelete, 0, 0L); } - private CompletableFuture purgeMessages(Integer amountToDelete, TextChannel channel, Long startId, Member purgedMember, Integer totalCount, Integer currentCount, Long statusMessageId) { + private CompletableFuture purgeMessages(Integer amountToDelete, GuildMessageChannel channel, Long startId, Member purgedMember, Integer totalCount, Integer currentCount, Long statusMessageId) { int toDeleteInThisIteration; if(amountToDelete >= PURGE_MAX_MESSAGES){ @@ -106,9 +103,12 @@ public class PurgeServiceBean implements PurgeService { return CompletableFuture.allOf(retrievalFuture, deletionFuture); } - private void bulkDeleteMessages(TextChannel channel, CompletableFuture deletionFuture, List messagesToDeleteNow, Consumer consumer) { + private void bulkDeleteMessages(GuildMessageChannel channel, CompletableFuture deletionFuture, List messagesToDeleteNow, Consumer consumer) { try { - channelService.deleteMessagesInChannel(channel, messagesToDeleteNow).queue(consumer, deletionFuture::completeExceptionally); + channelService.deleteMessagesInChannel(channel, messagesToDeleteNow).thenAccept(consumer).exceptionally(throwable -> { + deletionFuture.completeExceptionally(throwable); + return null; + }); } catch (IllegalArgumentException e) { channelService.sendTextToChannel(e.getMessage(), channel); log.warn("Failed to bulk delete, message was most likely too old to delete by bulk.", e); @@ -116,7 +116,7 @@ public class PurgeServiceBean implements PurgeService { } } - private CompletableFuture getOrCreatedStatusMessage(TextChannel channel, Integer totalCount, Long statusMessageId) { + private CompletableFuture getOrCreatedStatusMessage(GuildMessageChannel channel, Integer totalCount, Long statusMessageId) { CompletableFuture statusMessageFuture; if(statusMessageId == 0) { log.debug("Creating new status message in channel {} in server {} because of puring.", channel.getIdLong(), channel.getGuild().getId()); @@ -151,7 +151,7 @@ public class PurgeServiceBean implements PurgeService { return messagesToDeleteNow; } - private Consumer deletionConsumer(Integer amountToDelete, TextChannel channel, Member purgedMember, Integer totalCount, Integer currentCount, CompletableFuture deletionFuture, Long currentStatusMessageId, Message earliestMessage) { + private Consumer deletionConsumer(Integer amountToDelete, GuildMessageChannel channel, Member purgedMember, Integer totalCount, Integer currentCount, CompletableFuture deletionFuture, Long currentStatusMessageId, Message earliestMessage) { return aVoid -> { if (amountToDelete >= 1) { log.debug("Still more than 1 message to delete. Continuing."); @@ -181,7 +181,7 @@ public class PurgeServiceBean implements PurgeService { } @Override - public CompletableFuture purgeMessagesInChannel(Integer count, TextChannel channel, Message origin, Member purgingRestriction) { + public CompletableFuture purgeMessagesInChannel(Integer count, GuildMessageChannel channel, Message origin, Member purgingRestriction) { return purgeMessagesInChannel(count, channel, origin.getIdLong(), purgingRestriction); } diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/ReactionReportServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/ReactionReportServiceBean.java index 660e1de91..e3ad630bf 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/ReactionReportServiceBean.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/ReactionReportServiceBean.java @@ -17,6 +17,7 @@ import dev.sheldan.abstracto.moderation.model.template.listener.ReportReactionNo import dev.sheldan.abstracto.moderation.service.management.ModerationUserManagementService; import dev.sheldan.abstracto.moderation.service.management.ReactionReportManagementService; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import org.springframework.beans.factory.annotation.Autowired; @@ -92,7 +93,7 @@ public class ReactionReportServiceBean implements ReactionReportService { ReactionReport report = recentReportOptional.get(); log.info("Report is already present in channel {} with message {}. Updating field.", report.getReportChannel().getId(), report.getReportMessageId()); report.setReportCount(report.getReportCount() + 1); - TextChannel reportTextChannel = channelService.getTextChannelFromServer(serverId, report.getReportChannel().getId()); + GuildMessageChannel reportTextChannel = channelService.getMessageChannelFromServer(serverId, report.getReportChannel().getId()); return channelService.editFieldValueInMessage(reportTextChannel, report.getReportMessageId(), 0, report.getReportCount().toString()) .thenAccept(message -> self.updateModerationUserReportCooldown(reporter)); } diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBean.java index c65ef0462..dad60000b 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBean.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBean.java @@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.exception.ChannelNotInGuildException; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.service.ChannelService; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.TextChannel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/management/ReactionReportManagementServiceBean.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/management/ReactionReportManagementServiceBean.java index 105f73aeb..08c3f9291 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/management/ReactionReportManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/main/java/dev/sheldan/abstracto/moderation/service/management/ReactionReportManagementServiceBean.java @@ -35,7 +35,7 @@ public class ReactionReportManagementServiceBean implements ReactionReportManage @Override public ReactionReport createReactionReport(CachedMessage reportedMessage, Message reportMessage) { - AChannel reportChannel = channelManagementService.loadChannel(reportMessage.getTextChannel()); + AChannel reportChannel = channelManagementService.loadChannel(reportMessage.getChannel()); AChannel reportedChannel = channelManagementService.loadChannel(reportedMessage.getChannelId()); AUserInAServer reportedUser = userInServerManagementService.loadOrCreateUser(reportedMessage.getAuthorAsServerUser()); ReactionReport report = ReactionReport diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/command/SlowModeTest.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/command/SlowModeTest.java index 81675e664..219ad312e 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/command/SlowModeTest.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/command/SlowModeTest.java @@ -32,7 +32,7 @@ public class SlowModeTest { public void testExecuteSlowModeWithDurationCurrentChannel() { String duration = "1m"; CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(duration)); - when(slowModeService.setSlowMode(parameters.getChannel(), Duration.ofMinutes(1))).thenReturn(CompletableFuture.completedFuture(null)); + when(slowModeService.setSlowMode((TextChannel) parameters.getChannel(), Duration.ofMinutes(1))).thenReturn(CompletableFuture.completedFuture(null)); CompletableFuture result = testUnit.executeAsync(parameters); CommandTestUtilities.checkSuccessfulCompletionAsync(result); } @@ -41,7 +41,7 @@ public class SlowModeTest { public void testDisableSlowModeCurrentChannel() { String duration = "off"; CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(duration)); - when(slowModeService.setSlowMode(parameters.getChannel(), Duration.ZERO)).thenReturn(CompletableFuture.completedFuture(null)); + when(slowModeService.setSlowMode((TextChannel) parameters.getChannel(), Duration.ZERO)).thenReturn(CompletableFuture.completedFuture(null)); CompletableFuture result = testUnit.executeAsync(parameters); CommandTestUtilities.checkSuccessfulCompletionAsync(result); } diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBeanTest.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBeanTest.java deleted file mode 100644 index 0dd5eb6e5..000000000 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/PurgeServiceBeanTest.java +++ /dev/null @@ -1,300 +0,0 @@ -package dev.sheldan.abstracto.moderation.service; - -import dev.sheldan.abstracto.core.metric.service.MetricService; -import dev.sheldan.abstracto.core.service.ChannelService; -import dev.sheldan.abstracto.core.service.MessageService; -import dev.sheldan.abstracto.moderation.exception.NoMessageFoundException; -import dev.sheldan.abstracto.moderation.model.template.command.PurgeStatusUpdateModel; -import dev.sheldan.abstracto.core.templating.model.MessageToSend; -import dev.sheldan.abstracto.core.templating.service.TemplateService; -import net.dv8tion.jda.api.entities.*; -import net.dv8tion.jda.api.requests.RestAction; -import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; -import net.dv8tion.jda.api.utils.TimeUtil; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; - -import static org.mockito.Mockito.*; - -@RunWith(MockitoJUnitRunner.class) -public class PurgeServiceBeanTest { - - @InjectMocks - private PurgeServiceBean testUnit; - - @Mock - private ChannelService channelService; - - @Mock - private MessageService messageService; - - @Mock - private TemplateService templateService; - - @Mock - private MetricService metricService; - - @Mock - private TextChannel textChannel; - - @Mock - private Member purgedMember; - - private static final Long START_MESSAGE_ID = 4L; - private static final Long STATUS_MESSAGE_ID = 7L; - private static final Long AUTHOR_ID = 17L; - - @Mock - private User messageAuthor; - - @Mock - private Message firstMessage; - - @Mock - private Message secondMessage; - - @Mock - private Message thirdMessage; - - @Mock - private Message fourthMessage; - - @Mock - private MessageHistory history; - - @Mock - private MessageToSend firstStatusUpdateMessage; - - @Mock - private RestAction deleteMessagesAction; - - @Mock - private AuditableRestAction deleteStatusAction; - - @Mock - private Guild guild; - - private static final Long SERVER_ID = 1L; - - @Before - public void setup() { - when(textChannel.getGuild()).thenReturn(guild); - when(guild.getId()).thenReturn(SERVER_ID.toString()); - when(guild.getIdLong()).thenReturn(SERVER_ID); - } - - @Test - public void testPurgeMessageViaStartMessage() { - Integer amountToDelete = 50; - when(channelService.getHistoryOfChannel(textChannel, START_MESSAGE_ID, amountToDelete)).thenReturn(CompletableFuture.completedFuture(history)); - - setupOneMessageBatch(getDeletableMessageId(), getDeletableMessageId()); - - Message messageToStartOffAT = Mockito.mock(Message.class); - when(messageToStartOffAT.getIdLong()).thenReturn(START_MESSAGE_ID); - CompletableFuture futures = testUnit.purgeMessagesInChannel(amountToDelete, textChannel, messageToStartOffAT, purgedMember); - futures.whenComplete((aVoid, throwable) -> Assert.assertNull(throwable)); - verify(deleteStatusAction, times(1)).queueAfter(5, TimeUnit.SECONDS); - verify(messageService, times(1)).updateStatusMessage(eq(textChannel), anyLong(), any()); - verify(metricService, times(1)).incrementCounter(any(), eq((long) amountToDelete)); - } - - @Test - public void testPurgeMessageNotNoUser() { - Integer amountToDelete = 50; - when(channelService.getHistoryOfChannel(textChannel, START_MESSAGE_ID, amountToDelete)).thenReturn(CompletableFuture.completedFuture(history)); - - when(firstMessage.getId()).thenReturn(getDeletableMessageId().toString()); - when(secondMessage.getId()).thenReturn(getDeletableMessageId().toString()); - - setupFirstMessageHistoryMocks(); - setupStatusMessageMocks(); - mockQueueDoubleVoidConsumer(deleteMessagesAction); - CompletableFuture futures = testUnit.purgeMessagesInChannel(amountToDelete, textChannel, START_MESSAGE_ID, null); - futures.whenComplete((aVoid, throwable) -> Assert.assertNull(throwable)); - verify(deleteStatusAction, times(1)).queueAfter(5, TimeUnit.SECONDS); - verify(messageService, times(1)).updateStatusMessage(eq(textChannel), anyLong(), any()); - verify(metricService, times(1)).incrementCounter(any(), eq((long) amountToDelete)); - } - - @Test - public void testPurgeSingleMessage() { - Integer amountToDelete = 50; - when(channelService.getHistoryOfChannel(textChannel, START_MESSAGE_ID, amountToDelete)).thenReturn(CompletableFuture.completedFuture(history)); - - when(firstMessage.getId()).thenReturn(getDeletableMessageId().toString()); - when(firstMessage.getAuthor()).thenReturn(messageAuthor); - setupMembersWithAuthorId(); - - List messagesToDelete = Arrays.asList(firstMessage); - when(history.getRetrievedHistory()).thenReturn(messagesToDelete); - setupStatusMessageMocks(); - AuditableRestAction auditableRestAction = Mockito.mock(AuditableRestAction.class); - when(messageService.deleteMessageWithAction(firstMessage)).thenReturn(auditableRestAction); - mockQueueDoubleVoidConsumer(auditableRestAction); - CompletableFuture futures = testUnit.purgeMessagesInChannel(amountToDelete, textChannel, START_MESSAGE_ID, purgedMember); - futures.whenComplete((aVoid, throwable) -> Assert.assertNull(throwable)); - verify(deleteStatusAction, times(1)).queueAfter(5, TimeUnit.SECONDS); - verify(messageService, times(1)).updateStatusMessage(eq(textChannel), anyLong(), any()); - verify(metricService, times(1)).incrementCounter(any(), eq((long) amountToDelete)); - } - - @Test - public void testPurgeMessagesInTwoIterationsSecondIterationsTooOld() { - Integer amountToDelete = 150; - Long latestDeletedMessageId = getDeletableMessageId(); - when(channelService.getHistoryOfChannel(textChannel, START_MESSAGE_ID, amountToDelete - 50)).thenReturn(CompletableFuture.completedFuture(history)); - - MessageHistory secondHistory = Mockito.mock(MessageHistory.class); - when(channelService.getHistoryOfChannel(textChannel, latestDeletedMessageId, 50)).thenReturn(CompletableFuture.completedFuture(secondHistory)); - - when(secondMessage.getIdLong()).thenReturn(latestDeletedMessageId); - when(thirdMessage.getId()).thenReturn(getNotDeletableMessageId().toString()); - when(fourthMessage.getId()).thenReturn(getNotDeletableMessageId().toString()); - - setupOneMessageBatch(getDeletableMessageId(), latestDeletedMessageId); - - List secondMessagesToDelete = Arrays.asList(thirdMessage, fourthMessage); - when(secondHistory.getRetrievedHistory()).thenReturn(secondMessagesToDelete); - - - CompletableFuture futures = testUnit.purgeMessagesInChannel(amountToDelete, textChannel, START_MESSAGE_ID, purgedMember); - futures.whenComplete((aVoid, throwable) -> Assert.assertTrue(throwable.getCause() instanceof NoMessageFoundException)); - verify(deleteStatusAction, times(1)).queueAfter(5, TimeUnit.SECONDS); - verify(messageService, times(1)).updateStatusMessage(eq(textChannel), anyLong(), any()); - ArgumentCaptor deleted = ArgumentCaptor.forClass(Long.class); - verify(metricService, times(2)).incrementCounter(any(), deleted.capture()); - List capturedValues = deleted.getAllValues(); - Assert.assertEquals(2, capturedValues.size()); - Assert.assertEquals(100, capturedValues.get(0).longValue()); - Assert.assertEquals(50, capturedValues.get(1).longValue()); - } - - - @Test - public void testPurgeMessagesInTwoIterations() { - Integer amountToDelete = 150; - Long latestDeletedMessageId = getDeletableMessageId(); - when(channelService.getHistoryOfChannel(textChannel, START_MESSAGE_ID, amountToDelete - 50)).thenReturn(CompletableFuture.completedFuture(history)); - MessageHistory secondHistory = Mockito.mock(MessageHistory.class); - when(channelService.getHistoryOfChannel(textChannel, latestDeletedMessageId, 50)).thenReturn(CompletableFuture.completedFuture(secondHistory)); - - when(secondMessage.getIdLong()).thenReturn(latestDeletedMessageId); - - setupOneMessageBatch(getDeletableMessageId(), latestDeletedMessageId); - - setupFirstMessages(thirdMessage, getDeletableMessageId(), fourthMessage, latestDeletedMessageId, messageAuthor); - - RestAction secondDeleteMessagesAction = Mockito.mock(RestAction.class); - List secondMessagesToDelete = Arrays.asList(thirdMessage, fourthMessage); - when(secondHistory.getRetrievedHistory()).thenReturn(secondMessagesToDelete); - when(channelService.deleteMessagesInChannel(textChannel, secondMessagesToDelete)).thenReturn(secondDeleteMessagesAction); - - - mockQueueDoubleVoidConsumer(secondDeleteMessagesAction); - CompletableFuture futures = testUnit.purgeMessagesInChannel(amountToDelete, textChannel, START_MESSAGE_ID, purgedMember); - futures.whenComplete((aVoid, throwable) -> Assert.assertNull(throwable)); - verify(deleteStatusAction, times(1)).queueAfter(5, TimeUnit.SECONDS); - verify(messageService, times(2)).updateStatusMessage(eq(textChannel), anyLong(), any()); - ArgumentCaptor deleted = ArgumentCaptor.forClass(Long.class); - verify(metricService, times(2)).incrementCounter(any(), deleted.capture()); - List capturedValues = deleted.getAllValues(); - Assert.assertEquals(2, capturedValues.size()); - Assert.assertEquals(100, capturedValues.get(0).longValue()); - Assert.assertEquals(50, capturedValues.get(1).longValue()); - } - - @Test - public void testPurgeMessagesInOneIteration() { - Integer amountToDelete = 50; - when(channelService.getHistoryOfChannel(textChannel, START_MESSAGE_ID, amountToDelete)).thenReturn(CompletableFuture.completedFuture(history)); - - setupOneMessageBatch(getDeletableMessageId(), getDeletableMessageId()); - - CompletableFuture futures = testUnit.purgeMessagesInChannel(amountToDelete, textChannel, START_MESSAGE_ID, purgedMember); - futures.whenComplete((aVoid, throwable) -> Assert.assertNull(throwable)); - verify(deleteStatusAction, times(1)).queueAfter(5, TimeUnit.SECONDS); - verify(messageService, times(1)).updateStatusMessage(eq(textChannel), anyLong(), any()); - verify(metricService, times(1)).incrementCounter(any(), eq((long) amountToDelete)); - } - - @Test - public void testPurgeTooOldMessage() { - Integer amountToDelete = 50; - when(channelService.getHistoryOfChannel(textChannel, START_MESSAGE_ID, amountToDelete)).thenReturn(CompletableFuture.completedFuture(history)); - - when(firstMessage.getId()).thenReturn(getNotDeletableMessageId().toString()); - - when(history.getRetrievedHistory()).thenReturn(Arrays.asList(firstMessage)); - setupStatusMessageMocks(); - CompletableFuture futures = testUnit.purgeMessagesInChannel(amountToDelete, textChannel, START_MESSAGE_ID, purgedMember); - futures.whenComplete((aVoid, throwable) -> Assert.assertTrue(throwable.getCause() instanceof NoMessageFoundException)); - } - - private void setupOneMessageBatch(Long deletableMessageId, Long deletableMessageId2) { - setupFirstMessages(firstMessage, deletableMessageId, secondMessage, deletableMessageId2, messageAuthor); - setupMembersWithAuthorId(); - setupFirstMessageHistoryMocks(); - mockQueueDoubleVoidConsumer(deleteMessagesAction); - setupStatusMessageMocks(); - } - - public void mockQueueDoubleVoidConsumer(RestAction action) { - doAnswer(invocationOnMock -> { - Object consumerObj = invocationOnMock.getArguments()[0]; - if(consumerObj instanceof Consumer) { - Consumer consumer = (Consumer) consumerObj; - consumer.accept(null); - } - return null; - }).when(action).queue(any(Consumer.class), any(Consumer.class)); - } - - private void setupFirstMessageHistoryMocks() { - List messagesToDelete = Arrays.asList(firstMessage, secondMessage); - when(history.getRetrievedHistory()).thenReturn(messagesToDelete); - when(channelService.deleteMessagesInChannel(textChannel, messagesToDelete)).thenReturn(deleteMessagesAction); - } - - private void setupStatusMessageMocks() { - when(templateService.renderTemplateToMessageToSend(eq("purge_status_update"), any(PurgeStatusUpdateModel.class), eq(SERVER_ID))).thenReturn(firstStatusUpdateMessage); - when(messageService.createStatusMessageId(firstStatusUpdateMessage, textChannel)).thenReturn(CompletableFuture.completedFuture(STATUS_MESSAGE_ID)); - when(textChannel.deleteMessageById(STATUS_MESSAGE_ID)).thenReturn(deleteStatusAction); - } - - private void setupMembersWithAuthorId() { - when(messageAuthor.getIdLong()).thenReturn(AUTHOR_ID); - when(purgedMember.getIdLong()).thenReturn(AUTHOR_ID); - } - - private void setupFirstMessages(Message firstMessageToMock, Long firstMessageId, Message secondMessageToMock, Long secondMessageId, User author) { - when(firstMessageToMock.getId()).thenReturn(firstMessageId.toString()); - when(firstMessageToMock.getAuthor()).thenReturn(author); - when(secondMessageToMock.getId()).thenReturn(secondMessageId.toString()); - when(secondMessageToMock.getAuthor()).thenReturn(author); - } - - - - private Long getDeletableMessageId() { - return TimeUtil.getDiscordTimestamp((System.currentTimeMillis() - (7 * 24 * 60 * 60 * 1000))); - } - - private Long getNotDeletableMessageId() { - return TimeUtil.getDiscordTimestamp((System.currentTimeMillis() - (21 * 24 * 60 * 60 * 1000))); - } - -} diff --git a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBeanTest.java b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBeanTest.java index 4cd96a0b6..9ecb9d431 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-impl/src/test/java/dev/sheldan/abstracto/moderation/service/SlowModeServiceBeanTest.java @@ -6,7 +6,7 @@ import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.service.ChannelService; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.managers.ChannelManager; +import net.dv8tion.jda.api.managers.channel.ChannelManager; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; diff --git a/abstracto-application/abstracto-modules/moderation/moderation-int/pom.xml b/abstracto-application/abstracto-modules/moderation/moderation-int/pom.xml index 083e8bfa5..736d06a9d 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-int/pom.xml +++ b/abstracto-application/abstracto-modules/moderation/moderation-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules moderation - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/model/template/command/UnMuteLog.java b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/model/template/command/UnMuteLog.java index 626414dc3..ddf84c5de 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/model/template/command/UnMuteLog.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/model/template/command/UnMuteLog.java @@ -3,6 +3,7 @@ package dev.sheldan.abstracto.moderation.model.template.command; import dev.sheldan.abstracto.core.models.context.ServerContext; import dev.sheldan.abstracto.core.utils.MessageUtils; import dev.sheldan.abstracto.moderation.model.database.Mute; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -19,6 +20,7 @@ import java.time.Instant; @SuperBuilder @Setter @NoArgsConstructor +@AllArgsConstructor public class UnMuteLog extends ServerContext { /** * The un-muted Member, is null if the member left the server diff --git a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeService.java b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeService.java index a78072bbe..9ded1a738 100644 --- a/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeService.java +++ b/abstracto-application/abstracto-modules/moderation/moderation-int/src/main/java/dev/sheldan/abstracto/moderation/service/PurgeService.java @@ -1,12 +1,10 @@ package dev.sheldan.abstracto.moderation.service; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import java.util.concurrent.CompletableFuture; public interface PurgeService { - CompletableFuture purgeMessagesInChannel(Integer count, TextChannel channel, Long messageId, Member purgingRestriction); - CompletableFuture purgeMessagesInChannel(Integer count, TextChannel channel, Message origin, Member purgingRestriction); + CompletableFuture purgeMessagesInChannel(Integer count, GuildMessageChannel channel, Long messageId, Member purgingRestriction); + CompletableFuture purgeMessagesInChannel(Integer count, GuildMessageChannel channel, Message origin, Member purgingRestriction); } diff --git a/abstracto-application/abstracto-modules/moderation/pom.xml b/abstracto-application/abstracto-modules/moderation/pom.xml index a05c929d1..c831c2090 100644 --- a/abstracto-application/abstracto-modules/moderation/pom.xml +++ b/abstracto-application/abstracto-modules/moderation/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules abstracto-modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml b/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml index 40bebd118..90fa03afd 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules modmail - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailInitialButtonListener.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailInitialButtonListener.java new file mode 100644 index 000000000..14e4301d4 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/listener/ModMailInitialButtonListener.java @@ -0,0 +1,98 @@ +package dev.sheldan.abstracto.modmail.listener; + +import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.core.listener.ButtonClickedListenerResult; +import dev.sheldan.abstracto.core.listener.async.jda.ButtonClickedListener; +import dev.sheldan.abstracto.core.models.UndoActionInstance; +import dev.sheldan.abstracto.core.models.listener.ButtonClickedListenerModel; +import dev.sheldan.abstracto.core.service.*; +import dev.sheldan.abstracto.core.service.management.ComponentPayloadManagementService; +import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition; +import dev.sheldan.abstracto.modmail.model.dto.ServerChoicePayload; +import dev.sheldan.abstracto.modmail.model.dto.ServiceChoicesPayload; +import dev.sheldan.abstracto.modmail.service.ModMailThreadService; +import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; + +@Component +@Slf4j +public class ModMailInitialButtonListener implements ButtonClickedListener { + + @Autowired + private MemberService memberService; + + @Autowired + private ModMailThreadService modMailThreadService; + + @Autowired + private UndoActionService undoActionService; + + @Autowired + private MessageService messageService; + + @Autowired + private ComponentPayloadManagementService componentPayloadService; + + @Autowired + private ModMailInitialButtonListener self; + + @Autowired + private ChannelService channelService; + + @Override + public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) { + ServiceChoicesPayload choices = (ServiceChoicesPayload) model.getDeserializedPayload(); + + ServerChoicePayload chosenServer = choices.getChoices().get(model.getEvent().getComponentId()); + + Long userId = choices.getUserId(); + log.debug("Executing action for creationg a modmail thread in server {} for user {}.", chosenServer.getServerId(), userId); + ArrayList undoActions = new ArrayList<>(); + memberService.getMemberInServerAsync(chosenServer.getServerId(), userId) + .thenCompose(member -> channelService.retrieveMessageInChannel(model.getEvent().getChannel(), choices.getMessageId()) + .thenCompose(originalMessage -> { + try { + return modMailThreadService.createModMailThreadForUser(member, originalMessage, model.getEvent().getChannel(), true, undoActions); + } catch (Exception ex) { + log.error("Failed to setup thread correctly", ex); + undoActionService.performActions(undoActions); + return null; + } + }) + .thenAccept(unused -> self.cleanup(model))) + .exceptionally(throwable -> { + log.error("Failed to setup thread correctly", throwable); + undoActionService.performActions(undoActions); + return null; + }); + return ButtonClickedListenerResult.ACKNOWLEDGED; + } + + @Transactional + public void cleanup(ButtonClickedListenerModel model) { + ServiceChoicesPayload choices = (ServiceChoicesPayload) model.getDeserializedPayload(); + choices.getChoices().keySet().forEach(componentId -> componentPayloadService.deletePayload(componentId)); + } + + @Override + public Boolean handlesEvent(ButtonClickedListenerModel model) { + return ModMailThreadServiceBean.MODMAIL_INITIAL_ORIGIN.equals(model.getOrigin()) && !model.getEvent().isFromGuild(); + } + + @Override + public Integer getPriority() { + return ListenerPriority.LOW; + } + + @Override + public FeatureDefinition getFeature() { + return ModMailFeatureDefinition.MOD_MAIL; + } + +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java index ca6979b7c..4529ed0be 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailMessageServiceBean.java @@ -72,9 +72,9 @@ public class ModMailMessageServiceBean implements ModMailMessageService { .stream() .map(ServerChannelMessageUser::getMessageId) .collect(Collectors.toList()); - Optional textChannelFromServer = channelService.getTextChannelFromServerOptional(thread.getServer().getId(), thread.getChannel().getId()); + Optional textChannelFromServer = channelService.getMessageChannelFromServerOptional(thread.getServer().getId(), thread.getChannel().getId()); if(textChannelFromServer.isPresent()) { - TextChannel modMailThread = textChannelFromServer.get(); + GuildMessageChannel modMailThread = textChannelFromServer.get(); Long userId = thread.getUser().getUserReference().getId(); botService.getInstance().openPrivateChannelById(userId).queue(privateChannel -> { Optional latestThreadMessageOptional = messageIds @@ -125,7 +125,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService { } public CompletableFuture loadMoreMessages(Integer totalMessageCount, List messagesToLoad, - MessageHistory privateMessageHistory, TextChannel thread, + MessageHistory privateMessageHistory, GuildMessageChannel thread, MessageHistory threadMessageHistory, PrivateChannel dmChannel, List loadedMessages, Integer counter) { // TODO maybe find a better mechanism for this... one which does not lead to infinite loops, but also doesnt miss out on history if(counter.equals(totalMessageCount * 2)) { diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java index 047aa2cd3..fa0221078 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/service/ModMailThreadServiceBean.java @@ -1,7 +1,5 @@ package dev.sheldan.abstracto.modmail.service; -import com.jagrosh.jdautilities.commons.waiter.EventWaiter; -import com.jagrosh.jdautilities.menu.ButtonMenu; import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.core.metric.service.CounterMetric; @@ -26,8 +24,10 @@ import dev.sheldan.abstracto.modmail.exception.ModMailCategoryIdException; import dev.sheldan.abstracto.modmail.exception.ModMailThreadChannelNotFound; import dev.sheldan.abstracto.modmail.exception.ModMailThreadNotFoundException; import dev.sheldan.abstracto.modmail.model.ClosingContext; +import dev.sheldan.abstracto.modmail.model.dto.ServiceChoicesPayload; +import dev.sheldan.abstracto.modmail.model.template.ServerChoices; import dev.sheldan.abstracto.modmail.model.database.*; -import dev.sheldan.abstracto.modmail.model.dto.ServerChoice; +import dev.sheldan.abstracto.modmail.model.template.ServerChoice; import dev.sheldan.abstracto.modmail.model.template.*; import dev.sheldan.abstracto.modmail.service.management.ModMailMessageManagementService; import dev.sheldan.abstracto.modmail.service.management.ModMailRoleManagementService; @@ -125,9 +125,6 @@ public class ModMailThreadServiceBean implements ModMailThreadService { @Autowired private ModMailSubscriberManagementService modMailSubscriberManagementService; - @Autowired - private EventWaiter eventWaiter; - @Autowired private FeatureModeService featureModeService; @@ -146,6 +143,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService { @Autowired private MetricService metricService; + @Autowired + private ComponentService componentService; + + @Autowired + private ComponentPayloadService componentPayloadService; + public static final String MODMAIL_THREAD_METRIC = "modmail.threads"; public static final String MODMAIL_MESSAGE_METRIC = "modmail.messges"; public static final String ACTION = "action"; @@ -174,14 +177,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService { .tagList(Arrays.asList(MetricTag.getTag(MESSAGE_DIRECTION, "sent"))) .build(); - /** - * The emoji used when the user can decide for a server to open a mod mail thread in. - */ - private static List NUMBER_EMOJI = Arrays.asList("\u0031\u20e3", "\u0032\u20e3", "\u0033\u20e3", - "\u0034\u20e3", "\u0035\u20e3", "\u0036\u20e3", - "\u0037\u20e3", "\u0038\u20e3", "\u0039\u20e3", - "\u0040\u20e3"); - + public static final String MODMAIL_INITIAL_ORIGIN = "modmailInitial"; @Override public CompletableFuture createModMailThreadForUser(Member member, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated, List undoActions) { @@ -315,34 +311,29 @@ public class ModMailThreadServiceBean implements ModMailThreadService { @Override public void createModMailPrompt(AUser user, Message initialMessage) { - List knownServers = userInServerManagementService.getUserInAllServers(user.getId()); - // if the user doesnt exist in the servery set, we need to create the user first in all of them, in order to offer it - if(knownServers.isEmpty()) { - List mutualServers = initialMessage.getJDA().getMutualGuilds(initialMessage.getAuthor()); - mutualServers.forEach(guild -> { - AServer server = serverManagementService.loadServer(guild); - knownServers.add(userInServerManagementService.loadOrCreateUser(server, user)); - }); - } - if(!knownServers.isEmpty()) { - log.info("There are {} shared servers between user and the bot.", knownServers.size()); + List servers = new ArrayList<>(); + List mutualServers = initialMessage.getJDA().getMutualGuilds(initialMessage.getAuthor()); + mutualServers.forEach(guild -> { + AServer server = serverManagementService.loadServer(guild); + servers.add(server); + }); + if(!servers.isEmpty()) { + log.info("There are {} shared servers between user and the bot.", servers.size()); List availableGuilds = new ArrayList<>(); - HashMap choices = new HashMap<>(); - for (int i = 0; i < knownServers.size(); i++) { - AUserInAServer aUserInAServer = knownServers.get(i); + for (AServer server : servers) { // only take the servers in which mod mail is actually enabled, would not make much sense to make the // other servers available - if(featureFlagService.isFeatureEnabled(modMailFeatureConfig, aUserInAServer.getServerReference())) { - AServer serverReference = aUserInAServer.getServerReference(); + if (featureFlagService.isFeatureEnabled(modMailFeatureConfig, server)) { FullGuild guild = FullGuild .builder() - .guild(guildService.getGuildById(serverReference.getId())) - .server(serverReference) + .guild(guildService.getGuildById(server.getId())) + .server(server) + .build(); + ServerChoice serverChoice = ServerChoice + .builder() + .serverId(guild.getGuild().getIdLong()) + .serverName(guild.getGuild().getName()) .build(); - // TODO support more than this limited amount of servers - String reactionEmote = NUMBER_EMOJI.get(i); - ServerChoice serverChoice = ServerChoice.builder().guild(guild).reactionEmote(reactionEmote).build(); - choices.put(reactionEmote, aUserInAServer.getServerReference().getId()); availableGuilds.add(serverChoice); } } @@ -350,40 +341,30 @@ public class ModMailThreadServiceBean implements ModMailThreadService { // if more than 1 server is available, show a choice dialog ArrayList undoActions = new ArrayList<>(); if(availableGuilds.size() > 1) { + Map choices = new HashMap<>(); + ServerChoices serverChoices = ServerChoices + .builder() + .commonGuilds(choices) + .userId(initialMessage.getAuthor().getIdLong()) + .messageId(initialMessage.getIdLong()) + .build(); + availableGuilds.forEach(serverChoice -> choices.put(componentService.generateComponentId(), serverChoice)); ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel .builder() - .commonGuilds(availableGuilds) - .build(); - String text = templateService.renderTemplate("modmail_modal_server_choice", modMailServerChooserModel); - ButtonMenu menu = new ButtonMenu.Builder() - .setChoices(choices.keySet().toArray(new String[0])) - .setEventWaiter(eventWaiter) - .setDescription(text) - .setAction(reactionEmote -> { - Long chosenServerId = choices.get(reactionEmote.getEmoji()); - Long userId = initialMessage.getAuthor().getIdLong(); - log.debug("Executing action for creationg a modmail thread in server {} for user {}.", chosenServerId, userId); - memberService.getMemberInServerAsync(chosenServerId, userId).thenCompose(member -> { - try { - return self.createModMailThreadForUser(member, initialMessage, initialMessage.getChannel(), true, undoActions); - } catch (Exception exception) { - log.error("Setting up modmail thread for user {} in server {} failed.", userId, chosenServerId, exception); - CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(exception); - return future; - } - }).exceptionally(throwable -> { - log.error("Failed to load member {} for modmail in server {}.", userId, chosenServerId, throwable); - undoActionService.performActions(undoActions); - return null; - }); - }) + .choices(serverChoices) .build(); + MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_modal_server_choice", modMailServerChooserModel); + FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, initialMessage.getChannel())) + .thenAccept(unused -> self.persistInitialCallbacks(serverChoices)) + .exceptionally(throwable -> { + log.error("Failed to setup prompt message correctly", throwable); + undoActionService.performActions(undoActions); + return null; + }); log.debug("Displaying server choice message for user {} in channel {}.", user.getId(), initialMessage.getChannel().getId()); - menu.display(initialMessage.getChannel()); } else if(availableGuilds.size() == 1) { // if exactly one server is available, open the thread directly - Long chosenServerId = choices.get(availableGuilds.get(0).getReactionEmote()); + Long chosenServerId = availableGuilds.get(0).getServerId(); log.info("Only one server available to modmail. Directly opening modmail thread for user {} in server {}.", initialMessage.getAuthor().getId(), chosenServerId); memberService.getMemberInServerAsync(chosenServerId, initialMessage.getAuthor().getIdLong()).thenCompose(member -> { try { @@ -408,6 +389,13 @@ public class ModMailThreadServiceBean implements ModMailThreadService { } } + @Transactional + public void persistInitialCallbacks(ServerChoices choices) { + ServiceChoicesPayload payload = ServiceChoicesPayload.fromServerChoices(choices); + choices.getCommonGuilds().keySet().forEach(componentId -> + componentPayloadService.createButtonPayload(componentId, payload, MODMAIL_INITIAL_ORIGIN, null)); + } + /** * Method used to send the header of a newly created mod mail thread. This message contains information about @@ -446,10 +434,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService { @Transactional public CompletableFuture relayMessage(Message messageFromUser, Long serverId, Long channelId, Long modmailThreadId, Member member) { - Optional textChannelFromServer = channelService.getTextChannelFromServerOptional(serverId, channelId); + Optional textChannelFromServer = channelService.getMessageChannelFromServerOptional(serverId, channelId); if(textChannelFromServer.isPresent()) { - TextChannel textChannel = textChannelFromServer.get(); - return self.sendUserReply(textChannel, modmailThreadId, messageFromUser, member, true); + GuildMessageChannel guildMessageChannel = textChannelFromServer.get(); + return self.sendUserReply(guildMessageChannel, modmailThreadId, messageFromUser, member, true); } else { log.warn("Closing mod mail thread {}, because it seems the channel {} in server {} got deleted.", modmailThreadId, channelId, serverId); // in this case there was no text channel on the server associated with the mod mail thread @@ -464,14 +452,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService { * This message takes a received {@link Message} from a user, renders it to a new message to send and sends it to * the appropriate {@link ModMailThread} channel, the returned promise only returns if the message was dealt with on the user * side. - * @param textChannel The {@link TextChannel} in which the {@link ModMailThread} is being handled + * @param textChannel The {@link GuildMessageChannel} in which the {@link ModMailThread} is being handled * @param modMailThreadId The id of the modmail thread to which the received {@link Message} is a reply to, can be null, if it is null, its the initial message * @param messageFromUser The received message from the user * @param member The {@link Member} instance from the user the thread is about. It is used as author * @param modMailThreadExists Whether or not the modmail thread already exists and is persisted. * @return A {@link CompletableFuture} which resolves when the post processing of the message is completed (adding read notification, and storing messageIDs) */ - public CompletableFuture sendUserReply(TextChannel textChannel, Long modMailThreadId, Message messageFromUser, Member member, boolean modMailThreadExists) { + public CompletableFuture sendUserReply(GuildMessageChannel textChannel, Long modMailThreadId, Message messageFromUser, Member member, boolean modMailThreadExists) { List> subscriberMemberFutures = new ArrayList<>(); if(modMailThreadExists) { ModMailThread modMailThread = modMailThreadManagementService.getById(modMailThreadId); @@ -551,7 +539,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService { * @param messageFromUser The {@link Message} object which was sent from the user */ @Transactional - public void postProcessSendMessages(TextChannel textChannel, Message messageInModMailThread, Message messageFromUser) { + public void postProcessSendMessages(GuildMessageChannel textChannel, Message messageInModMailThread, Message messageFromUser) { Optional modMailThreadOpt = modMailThreadManagementService.getByChannelIdOptional(textChannel.getIdLong()); if(modMailThreadOpt.isPresent()) { ModMailThread modMailThread = modMailThreadOpt.get(); @@ -793,7 +781,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService { log.info("Modmail thread {} is empty. No messages to log.", modMailThreadId); return CompletableFuture.completedFuture(new CompletableFutureList<>(new ArrayList<>())); } - TextChannel channel = channelService.getTextChannelFromServer(serverId, modMailThreadId); + GuildMessageChannel channel = channelService.getMessageChannelFromServer(serverId, modMailThreadId); ClosingProgressModel progressModel = ClosingProgressModel .builder() .loggedMessages(0) diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedActionConfig.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedActionConfig.java index ae2a470c7..04b297281 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedActionConfig.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategoryDelayedActionConfig.java @@ -5,7 +5,6 @@ import dev.sheldan.abstracto.modmail.model.template.ModMailCategoryActionModel; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.Category; /** * This represents both an instance of a {@link DelayedActionConfig} used to be executed in the @@ -19,7 +18,6 @@ import net.dv8tion.jda.api.entities.Category; public class ModMailCategoryDelayedActionConfig implements DelayedActionConfig { private Long serverId; private Long categoryId; - private Category category; @Override public String getTemplateName() { @@ -30,7 +28,7 @@ public class ModMailCategoryDelayedActionConfig implements DelayedActionConfig { public Object getTemplateModel() { return ModMailCategoryActionModel .builder() - .category(this.category) + .serverId(serverId) .categoryId(categoryId) .build(); } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java index 74b9a5ebf..ac5492d80 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-impl/src/main/java/dev/sheldan/abstracto/modmail/setup/ModMailCategorySetupBean.java @@ -5,6 +5,7 @@ import dev.sheldan.abstracto.core.models.AServerChannelUserId; import dev.sheldan.abstracto.core.models.FeatureValidationResult; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; import dev.sheldan.abstracto.core.service.ConfigService; import dev.sheldan.abstracto.core.service.GuildService; import dev.sheldan.abstracto.core.service.management.ChannelManagementService; @@ -82,7 +83,10 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { Long categoryId = configService.getLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, user.getGuildId()); log.debug("Previous modmail category exists for server {}. Loading value {}.", guild.getId(), categoryId); Category category = guild.getCategoryById(categoryId); - model.setCategory(category); + if(category != null) { + model.setCategoryId(category.getIdLong()); + } + model.setServerId(user.getGuildId()); } log.info("Executing mod mail category setup for server {}.", user.getGuildId()); String messageText = templateService.renderTemplate(messageTemplateKey, model); @@ -90,8 +94,8 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { CompletableFuture future = new CompletableFuture<>(); AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(user.getGuildId(), user.getUserId()); - Runnable finalAction = getTimeoutRunnable(user.getGuildId(), user.getChannelId()); - Consumer configAction = (MessageReceivedEvent event) -> { + Consumer finalAction = getTimeoutConsumer(user.getGuildId(), user.getChannelId()); + Consumer configAction = (MessageReceivedModel event) -> { try { SetupStepResult result; @@ -113,10 +117,14 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { ModMailCategoryDelayedActionConfig build = ModMailCategoryDelayedActionConfig .builder() .serverId(user.getGuildId()) - .category(guild.getCategoryById(categoryId)) .categoryId(categoryId) .build(); - List delayedSteps = Arrays.asList(build); + DelayedActionConfigContainer container = DelayedActionConfigContainer + .builder() + .type(build.getClass()) + .object(build) + .build(); + List delayedSteps = Arrays.asList(container); result = SetupStepResult .builder() .result(SetupStepResultType.SUCCESS) @@ -135,12 +143,12 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup { future.completeExceptionally(new SetupStepException(e)); } }; - interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel, parameter.getPreviousMessageId(), configAction, finalAction); + interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel, configAction, finalAction); return future; } - protected Runnable getTimeoutRunnable(Long serverId, Long channelId) { - return () -> interactiveUtils.sendTimeoutMessage(serverId, channelId); + protected Consumer getTimeoutConsumer(Long serverId, Long channelId) { + return (MessageReceivedModel) -> interactiveUtils.sendTimeoutMessage(serverId, channelId); } protected boolean checkForExit(Message message) { diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/pom.xml b/abstracto-application/abstracto-modules/modmail/modmail-int/pom.xml index 8356e84a4..9a524767c 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/pom.xml +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules modmail - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/dto/ServerChoice.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/dto/ServerChoice.java deleted file mode 100644 index 52b2a2c77..000000000 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/dto/ServerChoice.java +++ /dev/null @@ -1,24 +0,0 @@ -package dev.sheldan.abstracto.modmail.model.dto; - -import dev.sheldan.abstracto.core.models.FullGuild; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; - -/** - * Used when the user shares multiple servers with the bot and needs to determine for which server the user - * wants to open a mod mail thread, this is done by reacting to the prompt with the proper emote. - */ -@Getter -@Setter -@Builder -public class ServerChoice { - /** - * The possible guild to open a mod mail thread for - */ - private FullGuild guild; - /** - * The unicode emote used in the prompt to identify this choice - */ - private String reactionEmote; -} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/dto/ServerChoicePayload.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/dto/ServerChoicePayload.java new file mode 100644 index 000000000..81fe73120 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/dto/ServerChoicePayload.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.modmail.model.dto; + +import dev.sheldan.abstracto.modmail.model.template.ServerChoice; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ServerChoicePayload { + private Long serverId; + + public static ServerChoicePayload fromServerChoice(ServerChoice choice) { + return ServerChoicePayload + .builder() + .serverId(choice.getServerId()) + .build(); + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/dto/ServiceChoicesPayload.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/dto/ServiceChoicesPayload.java new file mode 100644 index 000000000..2a6a78bab --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/dto/ServiceChoicesPayload.java @@ -0,0 +1,28 @@ +package dev.sheldan.abstracto.modmail.model.dto; + +import dev.sheldan.abstracto.core.models.template.button.ButtonPayload; +import dev.sheldan.abstracto.modmail.model.template.ServerChoices; +import lombok.Builder; +import lombok.Getter; + +import java.util.HashMap; +import java.util.Map; + +@Getter +@Builder +public class ServiceChoicesPayload implements ButtonPayload { + private Map choices; + private Long userId; + private Long messageId; + + public static ServiceChoicesPayload fromServerChoices(ServerChoices choices) { + Map newChoices = new HashMap<>(); + choices.getCommonGuilds().forEach((s, choice) -> newChoices.put(s, ServerChoicePayload.fromServerChoice(choice))); + return ServiceChoicesPayload + .builder() + .userId(choices.getUserId()) + .messageId(choices.getMessageId()) + .choices(newChoices) + .build(); + } +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailCategoryActionModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailCategoryActionModel.java index 9483c19ca..334d3bbb0 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailCategoryActionModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailCategoryActionModel.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.modmail.model.template; +import dev.sheldan.abstracto.core.utils.ChannelUtils; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -14,6 +15,10 @@ import net.dv8tion.jda.api.entities.Category; @Setter @Builder public class ModMailCategoryActionModel { - private Category category; + private Long serverId; private Long categoryId; + + public String getCategoryAsMention() { + return ChannelUtils.getAsMention(this.getCategoryId()); + } } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailServerChooserModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailServerChooserModel.java index c651a1c32..968dacb3e 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailServerChooserModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ModMailServerChooserModel.java @@ -1,12 +1,9 @@ package dev.sheldan.abstracto.modmail.model.template; -import dev.sheldan.abstracto.modmail.model.dto.ServerChoice; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import java.util.List; - /** * Container model used to define all the possible {@link ServerChoice} which are presented when the initial message is * sent to the bot @@ -15,9 +12,5 @@ import java.util.List; @Setter @Builder public class ModMailServerChooserModel { - /** - * A list of {@link ServerChoice} which contains the common servers of the user and the bot, but only those - * in which the mod mail feature is currently enabled - */ - private List commonGuilds; + private ServerChoices choices; } diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ServerChoice.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ServerChoice.java new file mode 100644 index 000000000..0aae2ba26 --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ServerChoice.java @@ -0,0 +1,11 @@ +package dev.sheldan.abstracto.modmail.model.template; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ServerChoice { + private String serverName; + private Long serverId; +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ServerChoices.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ServerChoices.java new file mode 100644 index 000000000..401bb772c --- /dev/null +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/ServerChoices.java @@ -0,0 +1,14 @@ +package dev.sheldan.abstracto.modmail.model.template; + +import lombok.Builder; +import lombok.Getter; + +import java.util.Map; + +@Getter +@Builder +public class ServerChoices { + private Map commonGuilds; + private Long userId; + private Long messageId; +} diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/SetupModMailCategoryMessageModel.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/SetupModMailCategoryMessageModel.java index e058216f7..652ee25da 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/SetupModMailCategoryMessageModel.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/model/template/SetupModMailCategoryMessageModel.java @@ -1,9 +1,9 @@ package dev.sheldan.abstracto.modmail.model.template; +import dev.sheldan.abstracto.core.utils.ChannelUtils; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.Category; /** * Model which is used when setting up the mod mail feature. The category property will be used when there is already a category @@ -13,5 +13,10 @@ import net.dv8tion.jda.api.entities.Category; @Setter @Builder public class SetupModMailCategoryMessageModel { - private Category category; + private Long serverId; + private Long categoryId; + + public String getCategoryAsMention() { + return ChannelUtils.getAsMention(this.getCategoryId()); + } } diff --git a/abstracto-application/abstracto-modules/modmail/pom.xml b/abstracto-application/abstracto-modules/modmail/pom.xml index 985ef4b9f..5d876523a 100644 --- a/abstracto-application/abstracto-modules/modmail/pom.xml +++ b/abstracto-application/abstracto-modules/modmail/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules abstracto-modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/pom.xml b/abstracto-application/abstracto-modules/pom.xml index 97fd1302b..f42621793 100644 --- a/abstracto-application/abstracto-modules/pom.xml +++ b/abstracto-application/abstracto-modules/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto abstracto-application - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/profanity-filter/pom.xml b/abstracto-application/abstracto-modules/profanity-filter/pom.xml index 43a827263..36b1a1c63 100644 --- a/abstracto-application/abstracto-modules/profanity-filter/pom.xml +++ b/abstracto-application/abstracto-modules/profanity-filter/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/profanity-filter/profanity-filter-impl/pom.xml b/abstracto-application/abstracto-modules/profanity-filter/profanity-filter-impl/pom.xml index 186202131..cecd07761 100644 --- a/abstracto-application/abstracto-modules/profanity-filter/profanity-filter-impl/pom.xml +++ b/abstracto-application/abstracto-modules/profanity-filter/profanity-filter-impl/pom.xml @@ -3,7 +3,7 @@ profanity-filter dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/profanity-filter/profanity-filter-int/pom.xml b/abstracto-application/abstracto-modules/profanity-filter/profanity-filter-int/pom.xml index 9fe9a5bff..94f5ca7d2 100644 --- a/abstracto-application/abstracto-modules/profanity-filter/profanity-filter-int/pom.xml +++ b/abstracto-application/abstracto-modules/profanity-filter/profanity-filter-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules profanity-filter - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/remind/pom.xml b/abstracto-application/abstracto-modules/remind/pom.xml index a85ca1840..427d2fba3 100644 --- a/abstracto-application/abstracto-modules/remind/pom.xml +++ b/abstracto-application/abstracto-modules/remind/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/remind/remind-impl/pom.xml b/abstracto-application/abstracto-modules/remind/remind-impl/pom.xml index 841133796..e2f1d3cf8 100644 --- a/abstracto-application/abstracto-modules/remind/remind-impl/pom.xml +++ b/abstracto-application/abstracto-modules/remind/remind-impl/pom.xml @@ -3,7 +3,7 @@ remind dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/remind/remind-impl/src/main/java/dev/sheldan/abstracto/remind/service/RemindServiceBean.java b/abstracto-application/abstracto-modules/remind/remind-impl/src/main/java/dev/sheldan/abstracto/remind/service/RemindServiceBean.java index cb79c23bd..50ea815d1 100644 --- a/abstracto-application/abstracto-modules/remind/remind-impl/src/main/java/dev/sheldan/abstracto/remind/service/RemindServiceBean.java +++ b/abstracto-application/abstracto-modules/remind/remind-impl/src/main/java/dev/sheldan/abstracto/remind/service/RemindServiceBean.java @@ -19,10 +19,7 @@ import dev.sheldan.abstracto.remind.service.management.ReminderManagementService import dev.sheldan.abstracto.scheduling.model.JobParameters; import dev.sheldan.abstracto.scheduling.service.SchedulerService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @@ -133,7 +130,7 @@ public class RemindServiceBean implements ReminderService { reminderId, channel.getId(), server.getId(), reminderToRemindFor.getRemindedUser().getUserReference().getId()); Optional guildToAnswerIn = guildService.getGuildByIdOptional(server.getId()); if(guildToAnswerIn.isPresent()) { - Optional channelToAnswerIn = channelService.getTextChannelFromServerOptional(server.getId(), channel.getId()); + Optional channelToAnswerIn = channelService.getMessageChannelFromServerOptional(server.getId(), channel.getId()); // only send the message if the channel still exists, if not, only set the reminder to reminded. if(channelToAnswerIn.isPresent()) { memberService.getMemberInServerAsync(server.getId(), reminderToRemindFor.getRemindedUser().getUserReference().getId()).thenAccept(member -> @@ -150,7 +147,7 @@ public class RemindServiceBean implements ReminderService { } @Transactional - public CompletableFuture sendReminderText(Long reminderId, TextChannel channelToAnswerIn, Member member) { + public CompletableFuture sendReminderText(Long reminderId, GuildMessageChannel channelToAnswerIn, Member member) { Reminder reminder = reminderManagementService.loadReminder(reminderId); log.debug("Sending remind message for reminder {} to user user {} in server {}.", reminderId, member.getIdLong(), member.getGuild().getIdLong()); ExecutedReminderModel build = ExecutedReminderModel diff --git a/abstracto-application/abstracto-modules/remind/remind-impl/src/test/java/dev/sheldan/abstracto/remind/service/RemindServiceBeanTest.java b/abstracto-application/abstracto-modules/remind/remind-impl/src/test/java/dev/sheldan/abstracto/remind/service/RemindServiceBeanTest.java index 4908def57..4ff6d8d10 100644 --- a/abstracto-application/abstracto-modules/remind/remind-impl/src/test/java/dev/sheldan/abstracto/remind/service/RemindServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/remind/remind-impl/src/test/java/dev/sheldan/abstracto/remind/service/RemindServiceBeanTest.java @@ -16,10 +16,7 @@ import dev.sheldan.abstracto.scheduling.model.JobParameters; import dev.sheldan.abstracto.scheduling.service.SchedulerService; import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.service.TemplateService; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -73,7 +70,7 @@ public class RemindServiceBeanTest { private Message message; @Mock - private TextChannel channel; + private GuildMessageChannel channel; @Mock private ScheduledExecutorService instantReminderScheduler; @@ -155,7 +152,7 @@ public class RemindServiceBeanTest { when(reminderManagementService.loadReminder(REMINDER_ID)).thenReturn(remindedReminder); Guild guildMock = Mockito.mock(Guild.class); when(guildService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guildMock)); - when(channelService.getTextChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.of(channel)); + when(channelService.getMessageChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.of(channel)); Member mockedMember = Mockito.mock(Member.class); when(memberService.getMemberInServerAsync(SERVER_ID, USER_ID)).thenReturn(CompletableFuture.completedFuture(mockedMember)); testUnit.executeReminder(REMINDER_ID); @@ -174,7 +171,7 @@ public class RemindServiceBeanTest { when(guildService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guildMock)); when(aUserInAServer.getUserReference()).thenReturn(user); when(remindedReminder.getRemindedUser()).thenReturn(aUserInAServer); - when(channelService.getTextChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.empty()); + when(channelService.getMessageChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.empty()); testUnit.executeReminder(REMINDER_ID); verify(reminderManagementService, times(1)).setReminded(remindedReminder); verify(self, times(0)).sendReminderText(anyLong(), any(), any(Member.class)); diff --git a/abstracto-application/abstracto-modules/remind/remind-int/pom.xml b/abstracto-application/abstracto-modules/remind/remind-int/pom.xml index 788a04290..0772e69f5 100644 --- a/abstracto-application/abstracto-modules/remind/remind-int/pom.xml +++ b/abstracto-application/abstracto-modules/remind/remind-int/pom.xml @@ -3,7 +3,7 @@ remind dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/repost-detection/pom.xml b/abstracto-application/abstracto-modules/repost-detection/pom.xml index 227cc2513..af8a3208c 100644 --- a/abstracto-application/abstracto-modules/repost-detection/pom.xml +++ b/abstracto-application/abstracto-modules/repost-detection/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/pom.xml b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/pom.xml index d555d110d..12829ab63 100644 --- a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/pom.xml +++ b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/pom.xml @@ -3,7 +3,7 @@ repost-detection dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/converter/RepostCheckChannelModelConverter.java b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/converter/RepostCheckChannelModelConverter.java index 4918569c1..6102934f3 100644 --- a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/converter/RepostCheckChannelModelConverter.java +++ b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/converter/RepostCheckChannelModelConverter.java @@ -26,7 +26,7 @@ public class RepostCheckChannelModelConverter { FullChannel .builder() .channel(channel) - .serverChannel(channelService.getTextChannelFromServerNullable(guild, channel.getId())) + .serverChannel(channelService.getMessageChannelFromServerNullable(guild, channel.getId())) .build() ).collect(Collectors.toList()); repostCheckChannelGroups.add( diff --git a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostMessageReceivedListener.java b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostMessageReceivedListener.java index 25f31c2d0..866e183b4 100644 --- a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostMessageReceivedListener.java +++ b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostMessageReceivedListener.java @@ -39,7 +39,7 @@ public class RepostMessageReceivedListener implements AsyncMessageReceivedListen if(!message.isFromGuild() || message.isWebhookMessage() || message.getType().isSystem()) { return DefaultListenerResult.IGNORED; } - AChannel channel = channelManagementService.loadChannel(message.getTextChannel().getIdLong()); + AChannel channel = channelManagementService.loadChannel(message.getChannel().getIdLong()); if(repostCheckChannelService.duplicateCheckEnabledForChannel(channel)) { repostService.processMessageAttachmentRepostCheck(message); List imageEmbeds = message.getEmbeds().stream().filter(messageEmbed -> messageEmbed.getType().equals(EmbedType.IMAGE)).collect(Collectors.toList()); diff --git a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/converter/RepostCheckChannelModelConverterTest.java b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/converter/RepostCheckChannelModelConverterTest.java index 8f7dcdb5e..597366570 100644 --- a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/converter/RepostCheckChannelModelConverterTest.java +++ b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/converter/RepostCheckChannelModelConverterTest.java @@ -62,11 +62,11 @@ public class RepostCheckChannelModelConverterTest { AChannel channel1 = Mockito.mock(AChannel.class); when(channel1.getId()).thenReturn(channelId1); TextChannel textChannel = Mockito.mock(TextChannel.class); - when(channelService.getTextChannelFromServerNullable(guild, channelId1)).thenReturn(textChannel); + when(channelService.getMessageChannelFromServerNullable(guild, channelId1)).thenReturn(textChannel); Long channelId2 = 2L; AChannel channel2 = Mockito.mock(AChannel.class); when(channel2.getId()).thenReturn(channelId2); - when(channelService.getTextChannelFromServerNullable(guild, channelId2)).thenReturn(null); + when(channelService.getMessageChannelFromServerNullable(guild, channelId2)).thenReturn(null); when(group.getChannels()).thenReturn(Arrays.asList(channel1, channel2)); RepostCheckChannelsModel model = testUnit.fromRepostCheckChannelGroups(Arrays.asList(element), guild); Assert.assertEquals(1, model.getRepostCheckChannelGroups().size()); diff --git a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostMessageReceivedListenerTest.java b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostMessageReceivedListenerTest.java index 83dbc9ca9..6ae89def5 100644 --- a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostMessageReceivedListenerTest.java +++ b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostMessageReceivedListenerTest.java @@ -42,7 +42,7 @@ public class RepostMessageReceivedListenerTest { private MessageReceivedModel model; @Mock - private TextChannel textChannel; + private GuildMessageChannel textChannel; @Captor private ArgumentCaptor> embedListCaptor; @@ -89,7 +89,7 @@ public class RepostMessageReceivedListenerTest { } private void setupRepostCheckEnabled(boolean b) { - when(message.getTextChannel()).thenReturn(textChannel); + when(message.getChannel()).thenReturn(textChannel); when(message.isFromGuild()).thenReturn(true); when(message.isWebhookMessage()).thenReturn(false); MessageType type = MessageType.DEFAULT; diff --git a/abstracto-application/abstracto-modules/repost-detection/repost-detection-int/pom.xml b/abstracto-application/abstracto-modules/repost-detection/repost-detection-int/pom.xml index 3da277095..00a4cb414 100644 --- a/abstracto-application/abstracto-modules/repost-detection/repost-detection-int/pom.xml +++ b/abstracto-application/abstracto-modules/repost-detection/repost-detection-int/pom.xml @@ -3,7 +3,7 @@ repost-detection dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/starboard/pom.xml b/abstracto-application/abstracto-modules/starboard/pom.xml index f8cea4c59..977fec2e0 100644 --- a/abstracto-application/abstracto-modules/starboard/pom.xml +++ b/abstracto-application/abstracto-modules/starboard/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/starboard/starboard-impl/pom.xml b/abstracto-application/abstracto-modules/starboard/starboard-impl/pom.xml index 2d4467886..728b1ff7b 100644 --- a/abstracto-application/abstracto-modules/starboard/starboard-impl/pom.xml +++ b/abstracto-application/abstracto-modules/starboard/starboard-impl/pom.xml @@ -3,7 +3,7 @@ starboard dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/starboard/starboard-impl/src/main/java/dev/sheldan/abstracto/starboard/service/StarboardServiceBean.java b/abstracto-application/abstracto-modules/starboard/starboard-impl/src/main/java/dev/sheldan/abstracto/starboard/service/StarboardServiceBean.java index 54c28e277..d3181d4c3 100644 --- a/abstracto-application/abstracto-modules/starboard/starboard-impl/src/main/java/dev/sheldan/abstracto/starboard/service/StarboardServiceBean.java +++ b/abstracto-application/abstracto-modules/starboard/starboard-impl/src/main/java/dev/sheldan/abstracto/starboard/service/StarboardServiceBean.java @@ -25,10 +25,7 @@ import dev.sheldan.abstracto.starboard.model.template.*; import dev.sheldan.abstracto.starboard.service.management.StarboardPostManagementService; import dev.sheldan.abstracto.starboard.service.management.StarboardPostReactorManagementService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -159,7 +156,7 @@ public class StarboardServiceBean implements StarboardService { } private StarboardPostModel createStarboardModel(CachedMessage message, Integer starCount, net.dv8tion.jda.api.entities.User user) { - Optional channel = channelService.getTextChannelFromServerOptional(message.getServerId(), message.getChannelId()); + Optional channel = channelService.getMessageChannelFromServerOptional(message.getServerId(), message.getChannelId()); Optional guild = guildService.getGuildByIdOptional(message.getServerId()); String starLevelEmote = getAppropriateEmote(message.getServerId(), starCount); return StarboardPostModel diff --git a/abstracto-application/abstracto-modules/starboard/starboard-impl/src/test/java/dev/sheldan/abstracto/starboard/service/StarboardServiceBeanTest.java b/abstracto-application/abstracto-modules/starboard/starboard-impl/src/test/java/dev/sheldan/abstracto/starboard/service/StarboardServiceBeanTest.java index f8c74ff16..d8da01475 100644 --- a/abstracto-application/abstracto-modules/starboard/starboard-impl/src/test/java/dev/sheldan/abstracto/starboard/service/StarboardServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/starboard/starboard-impl/src/test/java/dev/sheldan/abstracto/starboard/service/StarboardServiceBeanTest.java @@ -97,7 +97,7 @@ public class StarboardServiceBeanTest { private Message sendPost; @Mock - private TextChannel mockedTextChannel; + private GuildMessageChannel mockedTextChannel; @Mock private User starredJdaUser; @@ -156,7 +156,7 @@ public class StarboardServiceBeanTest { when(message.getServerId()).thenReturn(SERVER_ID); when(message.getChannelId()).thenReturn(CHANNEL_ID); when(userService.retrieveUserForId(STARRED_USER_ID)).thenReturn(CompletableFuture.completedFuture(starredJdaUser)); - when(channelService.getTextChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.of(mockedTextChannel)); + when(channelService.getMessageChannelFromServerOptional(SERVER_ID, CHANNEL_ID)).thenReturn(Optional.of(mockedTextChannel)); when(guildService.getGuildByIdOptional(SERVER_ID)).thenReturn(Optional.of(guild)); SystemConfigProperty config = Mockito.mock(SystemConfigProperty.class); Long defaultValue = 3L; diff --git a/abstracto-application/abstracto-modules/starboard/starboard-int/pom.xml b/abstracto-application/abstracto-modules/starboard/starboard-int/pom.xml index 32732b386..9452dc075 100644 --- a/abstracto-application/abstracto-modules/starboard/starboard-int/pom.xml +++ b/abstracto-application/abstracto-modules/starboard/starboard-int/pom.xml @@ -3,7 +3,7 @@ starboard dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/starboard/starboard-int/src/main/java/dev/sheldan/abstracto/starboard/model/template/StarboardPostModel.java b/abstracto-application/abstracto-modules/starboard/starboard-int/src/main/java/dev/sheldan/abstracto/starboard/model/template/StarboardPostModel.java index 2d39eab6c..94f8493c7 100644 --- a/abstracto-application/abstracto-modules/starboard/starboard-int/src/main/java/dev/sheldan/abstracto/starboard/model/template/StarboardPostModel.java +++ b/abstracto-application/abstracto-modules/starboard/starboard-int/src/main/java/dev/sheldan/abstracto/starboard/model/template/StarboardPostModel.java @@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.models.context.ServerContext; import lombok.Getter; import lombok.Setter; import lombok.experimental.SuperBuilder; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.User; @Getter @@ -13,7 +13,7 @@ import net.dv8tion.jda.api.entities.User; @SuperBuilder public class StarboardPostModel extends ServerContext { private User author; - private TextChannel channel; + private GuildMessageChannel channel; private Long sourceChannelId; private CachedMessage message; private Integer starCount; diff --git a/abstracto-application/abstracto-modules/statistic/pom.xml b/abstracto-application/abstracto-modules/statistic/pom.xml index e8eb3e2c7..0a0bf6237 100644 --- a/abstracto-application/abstracto-modules/statistic/pom.xml +++ b/abstracto-application/abstracto-modules/statistic/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules abstracto-modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/statistic/statistic-impl/pom.xml b/abstracto-application/abstracto-modules/statistic/statistic-impl/pom.xml index 2d92cb609..03d153503 100644 --- a/abstracto-application/abstracto-modules/statistic/statistic-impl/pom.xml +++ b/abstracto-application/abstracto-modules/statistic/statistic-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules statistic - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/pom.xml b/abstracto-application/abstracto-modules/statistic/statistic-int/pom.xml index 60c2927fa..79e8c7d4a 100644 --- a/abstracto-application/abstracto-modules/statistic/statistic-int/pom.xml +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules statistic - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/suggestion/pom.xml b/abstracto-application/abstracto-modules/suggestion/pom.xml index 7ec944b46..c12f1c38e 100644 --- a/abstracto-application/abstracto-modules/suggestion/pom.xml +++ b/abstracto-application/abstracto-modules/suggestion/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/pom.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/pom.xml index a015a5157..634f943af 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/pom.xml +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/pom.xml @@ -3,7 +3,7 @@ suggestion dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/listener/SuggestionButtonVoteClickedListener.java b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/listener/SuggestionButtonVoteClickedListener.java index aaa255bb7..347ed5831 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/listener/SuggestionButtonVoteClickedListener.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/listener/SuggestionButtonVoteClickedListener.java @@ -12,8 +12,8 @@ import dev.sheldan.abstracto.suggestion.model.template.SuggestionButtonPayload; import dev.sheldan.abstracto.suggestion.service.SuggestionServiceBean; import dev.sheldan.abstracto.suggestion.service.SuggestionVoteService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.interaction.ButtonClickEvent; -import net.dv8tion.jda.api.interactions.components.ButtonInteraction; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonInteraction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -33,7 +33,7 @@ public class SuggestionButtonVoteClickedListener implements ButtonClickedListene @Override public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) { - ButtonClickEvent event = model.getEvent(); + ButtonInteractionEvent event = model.getEvent(); SuggestionButtonPayload payload = (SuggestionButtonPayload) model.getDeserializedPayload(); suggestionVoteService.upsertSuggestionVote(event.getMember(), payload.getDecision(), payload.getSuggestionId()); ButtonInteraction buttonInteraction = model.getEvent().getInteraction(); @@ -58,7 +58,7 @@ public class SuggestionButtonVoteClickedListener implements ButtonClickedListene @Override public Boolean handlesEvent(ButtonClickedListenerModel model) { - return SuggestionServiceBean.SUGGESTION_VOTE_ORIGIN.equals(model.getOrigin()); + return SuggestionServiceBean.SUGGESTION_VOTE_ORIGIN.equals(model.getOrigin()) && model.getEvent().isFromGuild(); } @Override diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/pom.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-int/pom.xml index 568cc2c0f..9e7ff7bec 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-int/pom.xml +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/pom.xml @@ -3,7 +3,7 @@ suggestion dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/utility/pom.xml b/abstracto-application/abstracto-modules/utility/pom.xml index c29ece7e5..5a8169551 100644 --- a/abstracto-application/abstracto-modules/utility/pom.xml +++ b/abstracto-application/abstracto-modules/utility/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules abstracto-modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/utility/utility-impl/pom.xml b/abstracto-application/abstracto-modules/utility/utility-impl/pom.xml index b4114c5df..44f0a8d9b 100644 --- a/abstracto-application/abstracto-modules/utility/utility-impl/pom.xml +++ b/abstracto-application/abstracto-modules/utility/utility-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules utility - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/utility/utility-int/pom.xml b/abstracto-application/abstracto-modules/utility/utility-int/pom.xml index ffb586aa1..b76ef5161 100644 --- a/abstracto-application/abstracto-modules/utility/utility-int/pom.xml +++ b/abstracto-application/abstracto-modules/utility/utility-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules utility - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/voice-channel-context/pom.xml b/abstracto-application/abstracto-modules/voice-channel-context/pom.xml index a3f413653..3763278c7 100644 --- a/abstracto-application/abstracto-modules/voice-channel-context/pom.xml +++ b/abstracto-application/abstracto-modules/voice-channel-context/pom.xml @@ -3,7 +3,7 @@ abstracto-modules dev.sheldan.abstracto.modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/voice-channel-context/voice-channel-context-impl/pom.xml b/abstracto-application/abstracto-modules/voice-channel-context/voice-channel-context-impl/pom.xml index aee6a44e8..07398b2f6 100644 --- a/abstracto-application/abstracto-modules/voice-channel-context/voice-channel-context-impl/pom.xml +++ b/abstracto-application/abstracto-modules/voice-channel-context/voice-channel-context-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules voice-channel-context - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/voice-channel-context/voice-channel-context-int/pom.xml b/abstracto-application/abstracto-modules/voice-channel-context/voice-channel-context-int/pom.xml index bb863aa87..4cf98c484 100644 --- a/abstracto-application/abstracto-modules/voice-channel-context/voice-channel-context-int/pom.xml +++ b/abstracto-application/abstracto-modules/voice-channel-context/voice-channel-context-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules voice-channel-context - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/webservices/pom.xml b/abstracto-application/abstracto-modules/webservices/pom.xml index 1fd8e5d30..536655405 100644 --- a/abstracto-application/abstracto-modules/webservices/pom.xml +++ b/abstracto-application/abstracto-modules/webservices/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules abstracto-modules - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/webservices/webservices-impl/pom.xml b/abstracto-application/abstracto-modules/webservices/webservices-impl/pom.xml index e9c7de3eb..7a625caa5 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-impl/pom.xml +++ b/abstracto-application/abstracto-modules/webservices/webservices-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules webservices - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/pom.xml b/abstracto-application/abstracto-modules/webservices/webservices-int/pom.xml index 6c2c98ec3..d8c810791 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-int/pom.xml +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.modules webservices - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/bundle/pom.xml b/abstracto-application/bundle/pom.xml index 911fcae3c..77f7bfa7c 100644 --- a/abstracto-application/bundle/pom.xml +++ b/abstracto-application/bundle/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto abstracto-application - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/core/core-impl/pom.xml b/abstracto-application/core/core-impl/pom.xml index 621c2d92b..e603c4435 100644 --- a/abstracto-application/core/core-impl/pom.xml +++ b/abstracto-application/core/core-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.core core - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 jar diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/CommandReceivedHandler.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/CommandReceivedHandler.java index 34735ae31..89ba1777b 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/CommandReceivedHandler.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/CommandReceivedHandler.java @@ -139,25 +139,32 @@ public class CommandReceivedHandler extends ListenerAdapter { @Override @Transactional public void onMessageReceived(MessageReceivedEvent event) { - if(!event.isFromGuild()) { + if (!event.isFromGuild()) { return; } Message message = event.getMessage(); - if(!commandManager.isCommand(message)) { + if (!commandManager.isCommand(message)) { return; } metricService.incrementCounter(COMMANDS_PROCESSED_COUNTER); try { UnParsedCommandResult result = getUnparsedCommandResult(message); CompletableFuture parsingFuture = getParametersFromMessage(message, result); - parsingFuture.thenAccept(parsedParameters -> self.executeCommand(event, parsedParameters.getCommand(), parsedParameters.getParameters())); + parsingFuture.thenAccept(parsedParameters -> { + try { + self.executeCommand(event, parsedParameters.getCommand(), parsedParameters.getParameters()); + } catch (Exception e) { + reportException(event, null, e, String.format("Exception when executing command from message %d in message %d in guild %d." + , message.getIdLong(), event.getChannel().getIdLong(), event.getGuild().getIdLong())); + } + }); parsingFuture.exceptionally(throwable -> { self.reportException(event, result.getCommand(), throwable, "Exception when parsing command."); return null; }); } catch (Exception e) { reportException(event, null, e, String.format("Exception when executing command from message %d in message %d in guild %d." - , message.getIdLong(), event.getChannel().getIdLong(), event.getGuild().getIdLong())); + , message.getIdLong(), event.getChannel().getIdLong(), event.getGuild().getIdLong())); } } @@ -244,7 +251,7 @@ public class CommandReceivedHandler extends ListenerAdapter { .author(event.getMember()) .guild(event.getGuild()) .undoActions(new ArrayList<>()) - .channel(event.getTextChannel()) + .channel(event.getGuildChannel()) .message(event.getMessage()) .jda(event.getJDA()) .userInitiatedContext(userInitiatedContext); @@ -253,9 +260,9 @@ public class CommandReceivedHandler extends ListenerAdapter { CompletableFuture conditionResultFuture = commandService.isCommandExecutable(foundCommand, commandContext); conditionResultFuture.thenAccept(conditionResult -> { CommandResult commandResult = null; - if(conditionResult.isResult()) { + if (conditionResult.isResult()) { CommandConfiguration commandConfiguration = foundCommand.getConfiguration(); - if(commandConfiguration.isRequiresConfirmation()) { + if (commandConfiguration.isRequiresConfirmation()) { DriedCommandContext driedCommandContext = DriedCommandContext.buildFromCommandContext(commandContext); driedCommandContext.setCommandName(commandConfiguration.getName()); String confirmId = componentService.generateComponentId(); @@ -272,7 +279,7 @@ public class CommandReceivedHandler extends ListenerAdapter { FutureUtils.toSingleFutureGeneric(confirmationMessageFutures) .thenAccept(unused -> self.persistConfirmationCallbacks(model, confirmationMessageFutures.get(0).join())) .exceptionally(throwable -> self.handleFailedCommand(foundCommand, commandContext, throwable)); - } else if(commandConfiguration.isAsync()) { + } else if (commandConfiguration.isAsync()) { log.info("Executing async command {} for server {} in channel {} based on message {} by user {}.", commandConfiguration.getName(), commandContext.getGuild().getId(), commandContext.getChannel().getId(), commandContext.getMessage().getId(), commandContext.getAuthor().getId()); @@ -284,7 +291,7 @@ public class CommandReceivedHandler extends ListenerAdapter { } else { commandResult = CommandResult.fromCondition(conditionResult); } - if(commandResult != null) { + if (commandResult != null) { self.executePostCommandListener(foundCommand, commandContext, commandResult); } }).exceptionally(throwable -> handleFailedCommand(foundCommand, commandContext, throwable)); @@ -301,7 +308,7 @@ public class CommandReceivedHandler extends ListenerAdapter { @Transactional(isolation = Isolation.SERIALIZABLE) public CompletableFuture executeAsyncCommand(Command foundCommand, CommandContext commandContext) { return foundCommand.executeAsync(commandContext).thenAccept(result -> - executePostCommandListener(foundCommand, commandContext, result) + executePostCommandListener(foundCommand, commandContext, result) ).exceptionally(throwable -> { handleFailedCommand(foundCommand, commandContext, throwable); return null; @@ -314,13 +321,13 @@ public class CommandReceivedHandler extends ListenerAdapter { } @Transactional - public void reportException(Message message, TextChannel textChannel, Member member, Command foundCommand, Throwable throwable, String s) { - UserInitiatedServerContext userInitiatedContext = buildUserInitiatedServerContext(member, textChannel, member.getGuild()); + public void reportException(Message message, MessageChannel channel, Member member, Command foundCommand, Throwable throwable, String s) { + UserInitiatedServerContext userInitiatedContext = buildUserInitiatedServerContext(member, channel, member.getGuild()); CommandContext.CommandContextBuilder commandContextBuilder = CommandContext.builder() .author(member) .guild(message.getGuild()) .undoActions(new ArrayList<>()) - .channel(message.getTextChannel()) + .channel(message.getGuildChannel()) .message(message) .jda(message.getJDA()) .userInitiatedContext(userInitiatedContext); @@ -332,7 +339,7 @@ public class CommandReceivedHandler extends ListenerAdapter { @Transactional public void reportException(MessageReceivedEvent event, Command foundCommand, Throwable throwable, String s) { - reportException(event.getMessage(), event.getTextChannel(), event.getMember(), foundCommand, throwable, s); + reportException(event.getMessage(), event.getChannel(), event.getMember(), foundCommand, throwable, s); } private void validateCommandParameters(Parameters parameters, Command foundCommand) { @@ -344,13 +351,13 @@ public class CommandReceivedHandler extends ListenerAdapter { Parameter parameter = parameterList.get(Math.min(i, parameterList.size() - 1)); for (ParameterValidator parameterValidator : parameter.getValidators()) { boolean validate = parameterValidator.validate(parameters.getParameters().get(i)); - if(!validate) { + if (!validate) { log.debug("Parameter {} in command {} failed to validate.", parameter.getName(), commandConfiguration.getName()); throw new CommandParameterValidationException(parameterValidator.getParameters(), parameterValidator.getExceptionTemplateName(), parameter); } } } - if(commandConfiguration.getNecessaryParameterCount() > parameters.getParameters().size()) { + if (commandConfiguration.getNecessaryParameterCount() > parameters.getParameters().size()) { String nextParameterName = commandConfiguration.getParameters().get(commandConfiguration.getNecessaryParameterCount() - 1).getName(); throw new InsufficientParametersException(foundCommand, nextParameterName); } @@ -371,23 +378,23 @@ public class CommandReceivedHandler extends ListenerAdapter { return foundCommand.execute(commandContext); } - private UserInitiatedServerContext buildUserInitiatedServerContext(Member member, TextChannel textChannel, Guild guild) { + private UserInitiatedServerContext buildUserInitiatedServerContext(Member member, MessageChannel channel, Guild guild) { return UserInitiatedServerContext .builder() .member(member) - .messageChannel(textChannel) + .messageChannel(channel) .guild(guild) .build(); } private UserInitiatedServerContext buildUserInitiatedServerContext(MessageReceivedEvent event) { - return buildUserInitiatedServerContext(event.getMember(), event.getTextChannel(), event.getGuild()); + return buildUserInitiatedServerContext(event.getMember(), event.getChannel(), event.getGuild()); } - public CompletableFuture getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message){ + public CompletableFuture getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message) { List parsedParameters = new ArrayList<>(); List parameters = command.getConfiguration().getParameters(); - if(parameters == null || parameters.isEmpty()) { + if (parameters == null || parameters.isEmpty()) { return CompletableFuture.completedFuture(Parameters.builder().parameters(new ArrayList<>()).build()); } log.debug("Parsing parameters for command {} based on message {}.", command.getConfiguration().getName(), message.getId()); @@ -403,9 +410,9 @@ public class CommandReceivedHandler extends ListenerAdapter { // because we might ignore some parameters (for example referenced messages) in case the command does not use this as a parameter int parsedParameter = 0; for (int i = 0; i < unParsedCommandParameter.getParameters().size(); i++) { - if(parsedParameter < parameters.size() && !param.isRemainder()) { + if (parsedParameter < parameters.size() && !param.isRemainder()) { param = parameters.get(parsedParameter); - } else if(param.isRemainder()) { + } else if (param.isRemainder()) { param = parameters.get(parameters.size() - 1); } else { break; @@ -421,7 +428,7 @@ public class CommandReceivedHandler extends ListenerAdapter { parsedParameters.add(ParseResult.builder().parameter(param).result(future).build()); } else { Object result = handler.handle(value, iterators, param, message, command); - if(result != null) { + if (result != null) { parsedParameters.add(ParseResult.builder().parameter(param).result(result).build()); } } @@ -438,12 +445,12 @@ public class CommandReceivedHandler extends ListenerAdapter { } } - if(!futures.isEmpty()) { + if (!futures.isEmpty()) { CompletableFuture multipleFuturesFuture = new CompletableFuture<>(); CompletableFuture combinedFuture = FutureUtils.toSingleFuture(futures); combinedFuture.thenAccept(aVoid -> { List allParamResults = parsedParameters.stream().map(o -> { - if(o.getResult() instanceof CompletableFuture) { + if (o.getResult() instanceof CompletableFuture) { return ((CompletableFuture) o.getResult()).join(); } else { return o.getResult(); @@ -451,7 +458,7 @@ public class CommandReceivedHandler extends ListenerAdapter { }).collect(Collectors.toList()); List parseResults = new ArrayList<>(); for (int i = 0; i < allParamResults.size(); i++) { - if(allParamResults.get(i) != null) { + if (allParamResults.get(i) != null) { ParseResult parseResult = ParseResult .builder() .result(allParamResults.get(i)) @@ -501,28 +508,27 @@ public class CommandReceivedHandler extends ListenerAdapter { private List extractParametersFromParsed(List results) { List usableParameters = new ArrayList<>(); results.forEach(parseResult -> { - if(parseResult.getParameter().isRemainder() && !parseResult.getParameter().isListParam() && parseResult.getResult() instanceof String) { - if(usableParameters.isEmpty() || !(usableParameters.get(usableParameters.size() -1) instanceof String)) { + if (parseResult.getParameter().isRemainder() && !parseResult.getParameter().isListParam() && parseResult.getResult() instanceof String) { + if (usableParameters.isEmpty() || !(usableParameters.get(usableParameters.size() - 1) instanceof String)) { usableParameters.add(parseResult.getResult()); } else { int lastIndex = usableParameters.size() - 1; usableParameters.set(lastIndex, usableParameters.get(lastIndex).toString() + " " + parseResult.getResult().toString()); } - } else if(parseResult.getParameter().isListParam()) { - if(usableParameters.isEmpty()) { + } else if (parseResult.getParameter().isListParam()) { + if (usableParameters.isEmpty()) { ArrayList list = new ArrayList<>(); list.add(parseResult.getResult().toString()); usableParameters.add(list); } else { int lastIndex = usableParameters.size() - 1; - ((List)usableParameters.get(lastIndex)).add(parseResult.getResult()); + ((List) usableParameters.get(lastIndex)).add(parseResult.getResult()); } - } - else { + } else { usableParameters.add(parseResult.getResult()); } }); - return usableParameters; + return usableParameters; } @PostConstruct diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/listener/ConfirmationButtonClickedListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/listener/ConfirmationButtonClickedListener.java index 1b8f59298..9b4b45da5 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/listener/ConfirmationButtonClickedListener.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/listener/ConfirmationButtonClickedListener.java @@ -49,6 +49,9 @@ public class ConfirmationButtonClickedListener implements ButtonClickedListener public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) { CommandConfirmationPayload payload = (CommandConfirmationPayload) model.getDeserializedPayload(); DriedCommandContext commandCtx = payload.getCommandContext(); + if(commandCtx.getUserId() != model.getEvent().getUser().getIdLong()) { + return ButtonClickedListenerResult.IGNORED; + } if(payload.getAction().equals(CommandConfirmationPayload.CommandConfirmationAction.CONFIRM)) { log.info("Confirming command {} in server {} from message {} in channel {} with event {}.", commandCtx.getCommandName(), commandCtx.getServerId(), commandCtx.getMessageId(), @@ -103,7 +106,7 @@ public class ConfirmationButtonClickedListener implements ButtonClickedListener @Override public Boolean handlesEvent(ButtonClickedListenerModel model) { - return CommandReceivedHandler.COMMAND_CONFIRMATION_ORIGIN.equals(model.getOrigin()); + return CommandReceivedHandler.COMMAND_CONFIRMATION_ORIGIN.equals(model.getOrigin()) && model.getEvent().isFromGuild(); } @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/model/CommandServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/model/CommandServiceBean.java index fa49bf312..4de0a05c1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/model/CommandServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/model/CommandServiceBean.java @@ -248,7 +248,7 @@ public class CommandServiceBean implements CommandService { .build(); CommandContext context = CommandContext .builder() - .channel(message.getTextChannel()) + .channel(message.getGuildChannel()) .author(author) .guild(message.getGuild()) .jda(message.getJDA()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java index f61036c91..baf1631bd 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionServiceBean.java @@ -21,8 +21,7 @@ import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.entities.User; -import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; -import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -96,7 +95,7 @@ public class ExceptionServiceBean implements ExceptionService { } @Override - public void reportExceptionToGuildMessageReceivedContext(Throwable exception, GuildMessageReceivedEvent event) { + public void reportExceptionToGuildMessageReceivedContext(Throwable exception, MessageReceivedEvent event) { if(exception instanceof Templatable){ GenericExceptionModel model = buildMemberContext(exception, event.getMember()); String text = templateService.renderTemplate(MODEL_WRAPPER_TEMPLATE_KEY, model); @@ -107,7 +106,7 @@ public class ExceptionServiceBean implements ExceptionService { } @Override - public void reportExceptionToPrivateMessageReceivedContext(Throwable exception, PrivateMessageReceivedEvent event) { + public void reportExceptionToPrivateMessageReceivedContext(Throwable exception, MessageReceivedEvent event) { if(exception instanceof Templatable){ GenericExceptionModel model = buildPrivateMessageReceivedModel(exception, event.getAuthor()); String text = templateService.renderTemplate(MODEL_WRAPPER_TEMPLATE_KEY, model); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/PostTargetCommand.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/PostTargetCommand.java index 0563be783..37ab2fbcd 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/PostTargetCommand.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/PostTargetCommand.java @@ -21,9 +21,7 @@ import dev.sheldan.abstracto.core.service.management.PostTargetManagement; import dev.sheldan.abstracto.core.service.management.ServerManagementService; import dev.sheldan.abstracto.core.utils.FutureUtils; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.GuildChannel; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -61,7 +59,7 @@ public class PostTargetCommand extends AbstractConditionableCommand { posttargetDisplayModel.setPostTargets(new ArrayList<>()); List postTargetEntries = posttargetDisplayModel.getPostTargets(); postTargets.forEach(target -> { - Optional channelFromAChannel = channelService.getChannelFromAChannel(target.getChannelReference()); + Optional channelFromAChannel = channelService.getGuildMessageChannelFromAChannelOptional(target.getChannelReference()); PostTargetModelEntry targetEntry = PostTargetModelEntry .builder() .channel(channelFromAChannel.orElse(null)) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CoreConfig.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CoreConfig.java index f8f4b7e89..28c2144f7 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CoreConfig.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CoreConfig.java @@ -3,13 +3,11 @@ package dev.sheldan.abstracto.core.config; import ch.qos.logback.core.net.ssl.SecureRandomFactoryBean; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.jagrosh.jdautilities.commons.waiter.EventWaiter; import dev.sheldan.abstracto.core.logging.OkHttpLogger; import dev.sheldan.abstracto.core.metric.OkHttpMetrics; import dev.sheldan.abstracto.core.service.BotService; import okhttp3.OkHttpClient; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -18,8 +16,7 @@ import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.time.Instant; import java.time.OffsetDateTime; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; +import java.util.List; @Configuration public class CoreConfig { @@ -27,29 +24,33 @@ public class CoreConfig { @Autowired private BotService botService; - @Value("${abstracto.eventWaiter.threads}") - private Integer threadCount; - @Autowired private OkHttpMetrics okHttpMetrics; @Autowired private OkHttpLogger okHttpLogger; + @Autowired + private List customJsonSerializers; + + @Autowired + private List customJsonDeSerializers; + @Bean public Gson gson() { - return new GsonBuilder() + GsonBuilder builder = new GsonBuilder() .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeAdapter()) .registerTypeAdapter(Instant.class, new InstantTimeAdapter()) - .setPrettyPrinting().create(); - } - - - @Bean - public EventWaiter eventWaiter() { - ScheduledExecutorService scheduledExecutorService = - Executors.newScheduledThreadPool(threadCount); - return new EventWaiter(scheduledExecutorService, true); + .setPrettyPrinting(); + if(customJsonDeSerializers != null) { + customJsonDeSerializers.forEach(customJsonSerializer -> + builder.registerTypeAdapter(customJsonSerializer.getType(), customJsonSerializer)); + } + if(customJsonSerializers != null) { + customJsonSerializers.forEach(customJsonSerializer -> + builder.registerTypeAdapter(customJsonSerializer.getType(), customJsonSerializer)); + } + return builder.create(); } @Bean diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CustomJsonDeSerializer.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CustomJsonDeSerializer.java new file mode 100644 index 000000000..3cf77efc9 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CustomJsonDeSerializer.java @@ -0,0 +1,5 @@ +package dev.sheldan.abstracto.core.config; + +public interface CustomJsonDeSerializer { + Class getType(); +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CustomJsonSerializer.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CustomJsonSerializer.java new file mode 100644 index 000000000..29bdffa71 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/CustomJsonSerializer.java @@ -0,0 +1,5 @@ +package dev.sheldan.abstracto.core.config; + +public interface CustomJsonSerializer { + Class getType(); +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/ListenerExecutorConfig.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/ListenerExecutorConfig.java index 8f814bc03..a5bc8d226 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/ListenerExecutorConfig.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/ListenerExecutorConfig.java @@ -62,6 +62,11 @@ public class ListenerExecutorConfig { return executorService.setupExecutorFor("buttonClickedListener"); } + @Bean(name = "messageContextCommandExecutor") + public TaskExecutor messageContextCommandExecutor() { + return executorService.setupExecutorFor("messageContextCommandListener"); + } + @Bean(name = "emoteDeletedExecutor") public TaskExecutor emoteDeletedExecutor() { return executorService.setupExecutorFor("emoteDeletedListener"); @@ -117,6 +122,16 @@ public class ListenerExecutorConfig { return executorService.setupExecutorFor("channelGroupCreatedListener"); } + @Bean(name = "featureActivationExecutor") + public TaskExecutor featureActivationListener() { + return executorService.setupExecutorFor("featureActivationListener"); + } + + @Bean(name = "featureDeactivationExecutor") + public TaskExecutor featureDeactivationListener() { + return executorService.setupExecutorFor("featureDeactivationListener"); + } + @Bean(name = "serverJoinExecutor") public TaskExecutor serverJoinExecutor() { return executorService.setupExecutorFor("serverJoinListener"); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveButtonClickedListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveButtonClickedListener.java new file mode 100644 index 000000000..eeb6b640c --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveButtonClickedListener.java @@ -0,0 +1,86 @@ +package dev.sheldan.abstracto.core.interactive; + +import com.google.gson.Gson; +import dev.sheldan.abstracto.core.command.config.features.CoreFeatureDefinition; +import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.core.interactive.setup.payload.SetupConfirmationPayload; +import dev.sheldan.abstracto.core.listener.ButtonClickedListenerResult; +import dev.sheldan.abstracto.core.listener.async.jda.ButtonClickedListener; +import dev.sheldan.abstracto.core.models.listener.ButtonClickedListenerModel; +import dev.sheldan.abstracto.core.service.DelayedActionService; +import dev.sheldan.abstracto.core.service.FeatureSetupServiceBean; +import dev.sheldan.abstracto.core.service.management.ComponentPayloadManagementService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Component +@Slf4j +public class InteractiveButtonClickedListener implements ButtonClickedListener { + + @Autowired + private InteractiveButtonClickedListener self; + + @Autowired + private DelayedActionService delayedActionService; + + @Autowired + private ComponentPayloadManagementService componentPayloadManagementService; + + @Autowired + private FeatureSetupServiceBean featureSetupServiceBean; + + @Autowired + private Gson gson; + + @Override + public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) { + SetupConfirmationPayload payload = (SetupConfirmationPayload) model.getDeserializedPayload(); + try { + if(payload.getAction().equals(SetupConfirmationPayload.SetupConfirmationAction.CONFIRM)) { + self.executeDelayedSteps(payload.getActions()); + featureSetupServiceBean.notifyAboutCompletion(payload.getOrigin(), payload.getFeatureKey(), SetupStepResult.fromSuccess()); + return ButtonClickedListenerResult.ACKNOWLEDGED; + } else { + featureSetupServiceBean.notifyAboutCompletion(payload.getOrigin(), payload.getFeatureKey(), SetupStepResult.fromCancelled()); + return ButtonClickedListenerResult.IGNORED; + } + } finally { + cleanup(model, payload); + } + } + + private void cleanup(ButtonClickedListenerModel model, SetupConfirmationPayload payload) { + log.debug("Cleaning up component {} and {}.", payload.getOtherButtonComponentId(), model.getEvent().getComponentId()); + componentPayloadManagementService.deletePayloads(Arrays.asList(payload.getOtherButtonComponentId(), model.getEvent().getComponentId())); + } + + @Transactional + public void executeDelayedSteps(List actions) { + List delayedActionConfigs = new ArrayList<>(); + actions.forEach(container -> delayedActionConfigs.add(container.getObject())); + delayedActionService.executeDelayedActions(delayedActionConfigs); + + } + + @Override + public Boolean handlesEvent(ButtonClickedListenerModel model) { + return model.getDeserializedPayload() instanceof SetupConfirmationPayload && model.getEvent().isFromGuild(); + } + + @Override + public Integer getPriority() { + return ListenerPriority.MEDIUM; + } + + @Override + public FeatureDefinition getFeature() { + return CoreFeatureDefinition.CORE_FEATURE; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveMessageReceivedListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveMessageReceivedListener.java new file mode 100644 index 000000000..eca828dbf --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveMessageReceivedListener.java @@ -0,0 +1,84 @@ +package dev.sheldan.abstracto.core.interactive; + +import dev.sheldan.abstracto.core.command.config.features.CoreFeatureDefinition; +import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.interactive.setup.callback.MessageInteractionCallback; +import dev.sheldan.abstracto.core.listener.DefaultListenerResult; +import dev.sheldan.abstracto.core.listener.async.jda.AsyncMessageReceivedListener; +import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +@Component +public class InteractiveMessageReceivedListener implements AsyncMessageReceivedListener { + + // server -> channel -> user + // TODO timeout + private Map>> callbacks = new HashMap<>(); + + private static final Lock runTimeLock = new ReentrantLock(); + + @Override + public DefaultListenerResult execute(MessageReceivedModel model) { + if(executeCallback(model)) { + return DefaultListenerResult.PROCESSED; + } + return DefaultListenerResult.IGNORED; + } + + @Override + public FeatureDefinition getFeature() { + return CoreFeatureDefinition.CORE_FEATURE; + } + + public boolean executeCallback(MessageReceivedModel model) { + runTimeLock.lock(); + try { + if(callbacks.containsKey(model.getServerId())) { + Map> channelMap = callbacks.get(model.getServerId()); + if(channelMap.containsKey(model.getMessage().getChannel().getIdLong())) { + Map userMap = channelMap.get(model.getMessage().getChannel().getIdLong()); + if(userMap.containsKey(model.getMessage().getAuthor().getIdLong())) { + MessageInteractionCallback foundCallback = userMap.get(model.getMessage().getAuthor().getIdLong()); + if(foundCallback.getCondition() == null || foundCallback.getCondition().test(model)) { + userMap.remove(model.getMessage().getAuthor().getIdLong()); + foundCallback.getAction().accept(model); + return true; + } + } + } + } + } finally { + runTimeLock.unlock(); + } + return false; + } + + public void addCallback(MessageInteractionCallback interactiveCallBack) { + runTimeLock.lock(); + try { + Map> channelMap = new HashMap<>(); + if(callbacks.containsKey(interactiveCallBack.getServerId())) { + channelMap = callbacks.get(interactiveCallBack.getServerId()); + } else { + callbacks.put(interactiveCallBack.getServerId(), channelMap); + } + Map userMap = new HashMap<>(); + if(channelMap.containsKey(interactiveCallBack.getChannelId())) { + userMap = channelMap.get(interactiveCallBack.getChannelId()); + } else { + channelMap.put(interactiveCallBack.getChannelId(), userMap); + } + if(!userMap.containsKey(interactiveCallBack.getUserId())) { + userMap.put(interactiveCallBack.getUserId(), interactiveCallBack); + } + } finally { + runTimeLock.unlock(); + } + } + +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveServiceBean.java index 0e44ad0f4..44b0676b1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveServiceBean.java @@ -1,24 +1,15 @@ package dev.sheldan.abstracto.core.interactive; -import com.jagrosh.jdautilities.commons.waiter.EventWaiter; -import com.jagrosh.jdautilities.menu.ButtonMenu; +import dev.sheldan.abstracto.core.interactive.setup.callback.MessageInteractionCallback; import dev.sheldan.abstracto.core.models.database.AChannel; -import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; import dev.sheldan.abstracto.core.service.ChannelService; -import dev.sheldan.abstracto.core.service.EmoteService; -import dev.sheldan.abstracto.core.service.MessageService; import dev.sheldan.abstracto.core.templating.model.MessageToSend; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Emote; -import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.HashMap; -import java.util.Optional; -import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @Component @@ -29,76 +20,31 @@ public class InteractiveServiceBean implements InteractiveService { private ChannelService channelService; @Autowired - private EventWaiter eventWaiter; - - @Autowired - private MessageService messageService; - - @Autowired - private EmoteService emoteService; + private InteractiveMessageReceivedListener interactiveMessageReceivedListener; @Override - public void createMessageWithResponse(String messageText, AUserInAServer responder, AChannel channel, Long messageId, Consumer action, Runnable finalAction) { + public void createMessageWithResponse(String messageText, AUserInAServer responder, AChannel channel, Consumer action, Consumer timeoutAction) { channelService.sendTextToAChannel(messageText, channel); - Long channelId = channel.getId(); - eventWaiter.waitForEvent(MessageReceivedEvent.class, event -> { - if(event != null) { - return event.getAuthor().getIdLong() == responder.getUserReference().getId() && event.getMessage().getIdLong() != messageId && event.getMessage().getChannel().getIdLong() == channelId; - } - return false; - }, action, 1, TimeUnit.MINUTES, finalAction); + createMessageReceivedCallback(channel, responder, action, timeoutAction); } @Override - public void createMessageWithResponse(MessageToSend messageToSend, AUserInAServer responder, AChannel channel, Long messageId, Consumer action, Runnable finalAction) { + public void createMessageWithResponse(MessageToSend messageToSend, AUserInAServer responder, AChannel channel, + Consumer action, Consumer timeoutAction) { channelService.sendMessageEmbedToSendToAChannel(messageToSend, channel); - Long userId = responder.getUserReference().getId(); - eventWaiter.waitForEvent(MessageReceivedEvent.class, event -> { - if(event != null) { - return event.getAuthor().getIdLong() == userId && event.getMessage().getIdLong() != messageId; - } - return false; - }, action, 1, TimeUnit.MINUTES, finalAction); + createMessageReceivedCallback(channel, responder, action, timeoutAction); } - - @Override - public void createMessageWithConfirmation(String text, AUserInAServer responder, AChannel channel, Long messageId, Consumer confirmation, Consumer denial, Runnable finalAction) { - Long serverId = responder.getServerReference().getId(); - ButtonMenu.Builder builder = new ButtonMenu.Builder(); - HashMap> actions = new HashMap<>(); - - addEmoteToBuilder("confirmation", confirmation, serverId, builder, actions); - addEmoteToBuilder("denial", denial, serverId, builder, actions); - - ButtonMenu menu = builder - .setEventWaiter(eventWaiter) - .setDescription(text) - .setAction(reactionEmote -> { - if(reactionEmote.isEmoji()) { - actions.get(reactionEmote.getEmoji()).accept(null); - } else { - actions.get(reactionEmote.getEmote().getId()).accept(null); - } - }) + private void createMessageReceivedCallback(AChannel channel, AUserInAServer responder, Consumer action, Consumer timeoutAction) { + MessageInteractionCallback callBack = MessageInteractionCallback + .builder() + .serverId(channel.getServer().getId()) + .channelId(channel.getId()) + .userId(responder.getUserReference().getId()) + .action(action) + .timeoutAction(timeoutAction) .build(); - Optional textChannelInGuild = channelService.getTextChannelFromServerOptional(serverId, channel.getId()); - textChannelInGuild.ifPresent(menu::display); + interactiveMessageReceivedListener.addCallback(callBack); } - private void addEmoteToBuilder(String key, Consumer consumer, Long serverId, ButtonMenu.Builder builder, HashMap> actions) { - AEmote emoteOrFakeEmote = emoteService.getEmoteOrDefaultEmote(key, serverId); - if(Boolean.TRUE.equals(emoteOrFakeEmote.getCustom())){ - Optional emote = emoteService.getEmote(serverId, emoteOrFakeEmote); - emote.ifPresent(emote1 -> { - builder.addChoice(emote1); - actions.put(emote1.getId(), consumer); - }); - } else { - builder.addChoice(emoteOrFakeEmote.getEmoteKey()); - actions.put(emoteOrFakeEmote.getEmoteKey(), consumer); - } - } - - } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStep.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStep.java deleted file mode 100644 index 364fc57a5..000000000 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStep.java +++ /dev/null @@ -1,86 +0,0 @@ -package dev.sheldan.abstracto.core.interactive; - -import dev.sheldan.abstracto.core.models.AServerChannelUserId; -import dev.sheldan.abstracto.core.models.database.AChannel; -import dev.sheldan.abstracto.core.models.database.AUserInAServer; -import dev.sheldan.abstracto.core.models.template.commands.SetupSummaryModel; -import dev.sheldan.abstracto.core.service.DelayedActionService; -import dev.sheldan.abstracto.core.service.management.ChannelManagementService; -import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; -import dev.sheldan.abstracto.core.templating.service.TemplateService; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; - -@Component -@Slf4j -public class SetupSummaryStep extends AbstractConfigSetupStep { - - public static final String FEATURE_SETUP_CONFIRMATION_TEMPLATE_KEY = "feature_setup_confirmation"; - @Autowired - private InteractiveService interactiveService; - - @Autowired - private TemplateService templateService; - - @Autowired - private ChannelManagementService channelManagementService; - - @Autowired - private UserInServerManagementService userInServerManagementService; - - @Autowired - private DelayedActionService delayedActionService; - - @Autowired - private SetupSummaryStep self; - - @Override - public CompletableFuture execute(AServerChannelUserId user, SetupStepParameter generalParameter) { - SetupSummaryStepParameter parameter = (SetupSummaryStepParameter) generalParameter; - SetupSummaryModel model = SetupSummaryModel - .builder() - .actionConfigs(parameter.getDelayedActionList()) - .build(); - String messageToSend = templateService.renderTemplate(FEATURE_SETUP_CONFIRMATION_TEMPLATE_KEY, model, user.getGuildId()); - AChannel channel = channelManagementService.loadChannel(user.getChannelId()); - CompletableFuture future = new CompletableFuture<>(); - AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(user.getGuildId(), user.getUserId()); - Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId()); - log.info("Executing setup summary question step in server {} in channel {} from user {}.", user.getGuildId(), user.getChannelId(), user.getUserId()); - Consumer confirmation = (Void none) -> { - try { - log.info("Setup summary was confirmed. Executing {} steps.", parameter.getDelayedActionList().size()); - self.executeDelayedSteps(parameter); - SetupStepResult result = SetupStepResult - .builder() - .result(SetupStepResultType.SUCCESS) - .build(); - future.complete(result); - } catch (Exception e) { - log.error("Failed to execute {} delayed actions.", parameter.getDelayedActionList().size(), e); - future.completeExceptionally(e); - } - }; - - Consumer denial = (Void none) -> { - log.info("Setup summary was rejected. Cancelling execution of {} steps.", parameter.getDelayedActionList().size()); - SetupStepResult result = SetupStepResult - .builder() - .result(SetupStepResultType.CANCELLED) - .build(); - future.complete(result); - }; - interactiveService.createMessageWithConfirmation(messageToSend, aUserInAServer, channel, parameter.getPreviousMessageId(), confirmation, denial, finalAction); - return future; - } - - @Transactional - public void executeDelayedSteps(SetupSummaryStepParameter parameter) { - delayedActionService.executeDelayedActions(parameter.getDelayedActionList()); - } -} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStepParameter.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStepParameter.java index 8dff112fb..d4915aef1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStepParameter.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SetupSummaryStepParameter.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.core.interactive; +import dev.sheldan.abstracto.core.config.FeatureConfig; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -11,5 +12,6 @@ import java.util.List; @Builder public class SetupSummaryStepParameter implements SetupStepParameter { private Long previousMessageId; - private List delayedActionList; + private List delayedActionList; + private FeatureConfig featureConfig; } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/DelayedActionDeSerializer.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/DelayedActionDeSerializer.java new file mode 100644 index 000000000..7b1082c2a --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/DelayedActionDeSerializer.java @@ -0,0 +1,36 @@ +package dev.sheldan.abstracto.core.interactive.setup.action; + +import com.google.gson.*; +import dev.sheldan.abstracto.core.config.CustomJsonDeSerializer; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.interactive.DelayedActionConfig; +import dev.sheldan.abstracto.core.interactive.DelayedActionConfigContainer; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Type; + +@Component +public class DelayedActionDeSerializer implements JsonDeserializer, CustomJsonDeSerializer { + + @Override + public DelayedActionConfigContainer deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jdc) throws JsonParseException { + String foundTypeString = jdc.deserialize(jsonElement.getAsJsonObject().get("type"), String.class); + Class foundType = null; + try { + foundType = Class.forName(foundTypeString); + } catch (ClassNotFoundException e) { + throw new AbstractoRunTimeException(String.format("Class %s for de-serializing button payload not found.", foundTypeString)); + } + DelayedActionConfig foundObjectPayload = jdc.deserialize(jsonElement.getAsJsonObject().get("payload"), foundType); + return DelayedActionConfigContainer + .builder() + .type(foundType) + .object(foundObjectPayload) + .build(); + } + + @Override + public Class getType() { + return DelayedActionConfigContainer.class; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/DelayedActionSerializer.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/DelayedActionSerializer.java new file mode 100644 index 000000000..706cfc2f7 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/DelayedActionSerializer.java @@ -0,0 +1,29 @@ +package dev.sheldan.abstracto.core.interactive.setup.action; + +import com.google.gson.*; +import dev.sheldan.abstracto.core.config.CustomJsonSerializer; +import dev.sheldan.abstracto.core.interactive.DelayedActionConfigContainer; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Type; + +@Component +public class DelayedActionSerializer implements CustomJsonSerializer, JsonSerializer { + + @Override + public JsonElement serialize(DelayedActionConfigContainer container, Type type, JsonSerializationContext jsc) { + + if(container == null) { + return null; + } + JsonObject messageObj = new JsonObject(); + messageObj.add("type", jsc.serialize(container.getType().getCanonicalName())); + messageObj.add("payload", jsc.serialize(container.getObject())); + return messageObj; + } + + @Override + public Class getType() { + return DelayedActionConfigContainer.class; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetDelayedAction.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/PostTargetDelayedAction.java similarity index 78% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetDelayedAction.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/PostTargetDelayedAction.java index 5a1e975ec..bdec40064 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetDelayedAction.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/PostTargetDelayedAction.java @@ -1,5 +1,8 @@ -package dev.sheldan.abstracto.core.interactive; +package dev.sheldan.abstracto.core.interactive.setup.action; +import dev.sheldan.abstracto.core.interactive.DelayedAction; +import dev.sheldan.abstracto.core.interactive.DelayedActionConfig; +import dev.sheldan.abstracto.core.interactive.setup.action.config.PostTargetDelayedActionConfig; import dev.sheldan.abstracto.core.service.management.PostTargetManagement; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigDelayedAction.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/SystemConfigDelayedAction.java similarity index 76% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigDelayedAction.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/SystemConfigDelayedAction.java index b41394457..5ad2c3ba6 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigDelayedAction.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/SystemConfigDelayedAction.java @@ -1,5 +1,8 @@ -package dev.sheldan.abstracto.core.interactive; +package dev.sheldan.abstracto.core.interactive.setup.action; +import dev.sheldan.abstracto.core.interactive.DelayedAction; +import dev.sheldan.abstracto.core.interactive.DelayedActionConfig; +import dev.sheldan.abstracto.core.interactive.setup.action.config.SystemConfigDelayedActionConfig; import dev.sheldan.abstracto.core.service.ConfigService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -9,7 +12,6 @@ import org.springframework.stereotype.Component; @Slf4j public class SystemConfigDelayedAction implements DelayedAction { - @Autowired private ConfigService configService; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetDelayedActionConfig.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/config/PostTargetDelayedActionConfig.java similarity index 80% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetDelayedActionConfig.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/config/PostTargetDelayedActionConfig.java index 9265883fa..36d77ba58 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetDelayedActionConfig.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/config/PostTargetDelayedActionConfig.java @@ -1,10 +1,10 @@ -package dev.sheldan.abstracto.core.interactive; +package dev.sheldan.abstracto.core.interactive.setup.action.config; +import dev.sheldan.abstracto.core.interactive.DelayedActionConfig; import dev.sheldan.abstracto.core.models.template.commands.PostTargetActionModel; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.TextChannel; @Getter @Setter @@ -14,7 +14,6 @@ public class PostTargetDelayedActionConfig implements DelayedActionConfig { private String postTargetKey; private Long serverId; private Long channelId; - private TextChannel textChannel; @Override public String getTemplateName() { @@ -26,7 +25,6 @@ public class PostTargetDelayedActionConfig implements DelayedActionConfig { return PostTargetActionModel .builder() .channelId(channelId) - .channel(textChannel) .postTargetKey(postTargetKey) .build(); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigDelayedActionConfig.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/config/SystemConfigDelayedActionConfig.java similarity index 78% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigDelayedActionConfig.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/config/SystemConfigDelayedActionConfig.java index 285a39b67..77c0cda45 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigDelayedActionConfig.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/action/config/SystemConfigDelayedActionConfig.java @@ -1,5 +1,6 @@ -package dev.sheldan.abstracto.core.interactive; +package dev.sheldan.abstracto.core.interactive.setup.action.config; +import dev.sheldan.abstracto.core.interactive.DelayedActionConfig; import dev.sheldan.abstracto.core.models.database.AConfig; import dev.sheldan.abstracto.core.models.template.commands.SystemConfigActionModel; import lombok.Builder; @@ -12,6 +13,7 @@ import lombok.Setter; public class SystemConfigDelayedActionConfig implements DelayedActionConfig { private String configKey; private Long serverId; + // not an actual value stored in the database, just used as a container private AConfig value; @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/callback/MessageInteractionCallback.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/callback/MessageInteractionCallback.java new file mode 100644 index 000000000..bfceb5a72 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/callback/MessageInteractionCallback.java @@ -0,0 +1,22 @@ +package dev.sheldan.abstracto.core.interactive.setup.callback; + +import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; +import lombok.Builder; +import lombok.Getter; + +import java.time.Instant; +import java.util.function.Consumer; +import java.util.function.Predicate; + +@Builder +@Getter +public class MessageInteractionCallback { + private Long serverId; + private Long channelId; + private Long userId; + private Consumer action; + private Consumer timeoutAction; + private Instant timeoutPoint; + + public Predicate condition; +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/NoChannelProvidedException.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/exception/NoChannelProvidedException.java similarity index 89% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/NoChannelProvidedException.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/exception/NoChannelProvidedException.java index 73fe6fa28..3d8fe25be 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/NoChannelProvidedException.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/exception/NoChannelProvidedException.java @@ -1,4 +1,4 @@ -package dev.sheldan.abstracto.core.interactive; +package dev.sheldan.abstracto.core.interactive.setup.exception; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.core.templating.Templatable; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/payload/SetupConfirmationPayload.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/payload/SetupConfirmationPayload.java new file mode 100644 index 000000000..d93c078ea --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/payload/SetupConfirmationPayload.java @@ -0,0 +1,23 @@ +package dev.sheldan.abstracto.core.interactive.setup.payload; + +import dev.sheldan.abstracto.core.interactive.DelayedActionConfigContainer; +import dev.sheldan.abstracto.core.models.AServerChannelUserId; +import dev.sheldan.abstracto.core.models.template.button.ButtonPayload; +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Getter +@Builder +public class SetupConfirmationPayload implements ButtonPayload { + private SetupConfirmationAction action; + private String featureKey; + private AServerChannelUserId origin; + private String otherButtonComponentId; + private List actions; + + public enum SetupConfirmationAction { + CONFIRM, ABORT + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetSetupStep.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/step/PostTargetSetupStep.java similarity index 79% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetSetupStep.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/step/PostTargetSetupStep.java index 81bb66c40..1a0566595 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/PostTargetSetupStep.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/step/PostTargetSetupStep.java @@ -1,9 +1,13 @@ -package dev.sheldan.abstracto.core.interactive; +package dev.sheldan.abstracto.core.interactive.setup.step; +import dev.sheldan.abstracto.core.interactive.*; +import dev.sheldan.abstracto.core.interactive.setup.action.config.PostTargetDelayedActionConfig; +import dev.sheldan.abstracto.core.interactive.setup.exception.NoChannelProvidedException; import dev.sheldan.abstracto.core.models.AServerChannelUserId; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.PostTarget; +import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; import dev.sheldan.abstracto.core.models.template.commands.SetupPostTargetMessageModel; import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ConfigService; @@ -12,9 +16,9 @@ import dev.sheldan.abstracto.core.service.management.PostTargetManagement; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.templating.service.TemplateService; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -55,10 +59,10 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep { @Override public CompletableFuture execute(AServerChannelUserId user, SetupStepParameter parameter) { PostTargetStepParameter postTargetStepParameter = (PostTargetStepParameter) parameter; - TextChannel currentTextChannel; + GuildMessageChannel currentTextChannel; if(postTargetManagement.postTargetExists(postTargetStepParameter.getPostTargetKey(), user.getGuildId())) { PostTarget postTarget = postTargetManagement.getPostTarget(postTargetStepParameter.getPostTargetKey(), user.getGuildId()); - currentTextChannel = channelService.getTextChannelFromServerOptional(user.getGuildId(), postTarget.getChannelReference().getId()).orElse(null); + currentTextChannel = channelService.getMessageChannelFromServerOptional(user.getGuildId(), postTarget.getChannelReference().getId()).orElse(null); } else { currentTextChannel = null; } @@ -71,9 +75,9 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep { AChannel channel = channelManagementService.loadChannel(user.getChannelId()); CompletableFuture future = new CompletableFuture<>(); AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(user.getGuildId(), user.getUserId()); - Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId()); + Consumer finalAction = super.getTimeoutConsumer(user.getGuildId(), user.getChannelId()); log.debug("Executing setup for post target {} in server {} for user {}.", postTargetStepParameter.getPostTargetKey(), user.getGuildId(), user.getUserId()); - Consumer configAction = (MessageReceivedEvent event) -> { + Consumer configAction = (MessageReceivedModel event) -> { try { SetupStepResult result; @@ -82,7 +86,7 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep { log.info("Setup has been cancelled, because of 'exit' message."); result = SetupStepResult.fromCancelled(); } else { - if(message.getMentionedChannels().size() == 0) { + if(message.getMentionedChannels().isEmpty()) { log.debug("No mentioned channel was seen in channel, nothing provided."); throw new NoChannelProvidedException(); } @@ -91,11 +95,15 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep { .builder() .postTargetKey(postTargetStepParameter.getPostTargetKey()) .serverId(user.getGuildId()) - .textChannel(textChannel) .channelId(textChannel.getIdLong()) .build(); log.debug("Setup for post target {} in server {} for user {} completed. Storing delayed action.", postTargetStepParameter.getPostTargetKey(), user.getGuildId(), user.getUserId()); - List delayedSteps = Arrays.asList(build); + DelayedActionConfigContainer container = DelayedActionConfigContainer + .builder() + .type(build.getClass()) + .object(build) + .build(); + List delayedSteps = Arrays.asList(container); result = SetupStepResult .builder() .result(SetupStepResultType.SUCCESS) @@ -109,7 +117,7 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep { future.completeExceptionally(new SetupStepException(e)); } }; - interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel, parameter.getPreviousMessageId(), configAction, finalAction); + interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel, configAction, finalAction); return future; } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/step/SetupSummaryStep.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/step/SetupSummaryStep.java new file mode 100644 index 000000000..58bee65a6 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/step/SetupSummaryStep.java @@ -0,0 +1,109 @@ +package dev.sheldan.abstracto.core.interactive.setup.step; + +import dev.sheldan.abstracto.core.interactive.*; +import dev.sheldan.abstracto.core.interactive.setup.payload.SetupConfirmationPayload; +import dev.sheldan.abstracto.core.models.AServerChannelUserId; +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.models.template.commands.SetupSummaryModel; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.service.ComponentPayloadService; +import dev.sheldan.abstracto.core.service.ComponentService; +import dev.sheldan.abstracto.core.service.DelayedActionService; +import dev.sheldan.abstracto.core.service.management.ChannelManagementService; +import dev.sheldan.abstracto.core.service.management.ServerManagementService; +import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; +import dev.sheldan.abstracto.core.templating.model.MessageToSend; +import dev.sheldan.abstracto.core.templating.service.TemplateService; +import dev.sheldan.abstracto.core.utils.FutureUtils; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Message; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +@Slf4j +public class SetupSummaryStep extends AbstractConfigSetupStep { + + public static final String FEATURE_SETUP_CONFIRMATION_TEMPLATE_KEY = "feature_setup_confirmation"; + public static final String SETUP_SUMMARY_ORIGIN = "setupSummary"; + @Autowired + private InteractiveService interactiveService; + + @Autowired + private TemplateService templateService; + + @Autowired + private ChannelManagementService channelManagementService; + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Autowired + private DelayedActionService delayedActionService; + + @Autowired + private SetupSummaryStep self; + + @Autowired + private ServerManagementService serverManagementService; + + @Autowired + private ComponentService componentService; + + @Autowired + private ChannelService channelService; + + @Autowired + private ComponentPayloadService componentPayloadService; + + @Override + public CompletableFuture execute(AServerChannelUserId user, SetupStepParameter generalParameter) { + SetupSummaryStepParameter parameter = (SetupSummaryStepParameter) generalParameter; + SetupSummaryModel model = SetupSummaryModel + .builder() + .actionConfigs(parameter.getDelayedActionList()) + .build(); + String confirmId = componentService.generateComponentId(); + String abortId = componentService.generateComponentId(); + model.setCancelButtonId(abortId); + model.setConfirmButtonId(confirmId); + MessageToSend message = templateService.renderEmbedTemplate(FEATURE_SETUP_CONFIRMATION_TEMPLATE_KEY, model, user.getGuildId()); + AChannel channel = channelManagementService.loadChannel(user.getChannelId()); + List> confirmationMessageFutures = channelService.sendMessageEmbedToSendToAChannel(message, channel); + return FutureUtils.toSingleFutureGeneric(confirmationMessageFutures) + .thenAccept(unused -> self.persistConfirmationCallbacks(model, user, parameter)) + .thenApply(unused -> SetupStepResult.builder().result(SetupStepResultType.SUCCESS).build()); + } + + @Transactional + public void persistConfirmationCallbacks(SetupSummaryModel model, AServerChannelUserId origin, SetupSummaryStepParameter parameter) { + AServer server = serverManagementService.loadServer(origin.getGuildId()); + + SetupConfirmationPayload confirmPayload = SetupConfirmationPayload + .builder() + .otherButtonComponentId(model.getConfirmButtonId()) + .origin(origin) + .actions(model.getActionConfigs()) + .featureKey(parameter.getFeatureConfig().getFeature().getKey()) + .action(SetupConfirmationPayload.SetupConfirmationAction.CONFIRM) + .build(); + + componentPayloadService.createButtonPayload(model.getConfirmButtonId(), confirmPayload, SETUP_SUMMARY_ORIGIN, server); + SetupConfirmationPayload cancelPayload = SetupConfirmationPayload + .builder() + .otherButtonComponentId(model.getCancelButtonId()) + .origin(origin) + .actions(model.getActionConfigs()) + .featureKey(parameter.getFeatureConfig().getFeature().getKey()) + .action(SetupConfirmationPayload.SetupConfirmationAction.ABORT) + .build(); + + componentPayloadService.createButtonPayload(model.getCancelButtonId(), cancelPayload, SETUP_SUMMARY_ORIGIN, server); + } + +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigSetupStep.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/step/SystemConfigSetupStep.java similarity index 86% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigSetupStep.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/step/SystemConfigSetupStep.java index c5b9bb980..5ebc4d6ca 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/SystemConfigSetupStep.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/interactive/setup/step/SystemConfigSetupStep.java @@ -1,5 +1,8 @@ -package dev.sheldan.abstracto.core.interactive; +package dev.sheldan.abstracto.core.interactive.setup.step; +import dev.sheldan.abstracto.core.interactive.*; +import dev.sheldan.abstracto.core.interactive.setup.action.config.SystemConfigDelayedActionConfig; +import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; import dev.sheldan.abstracto.core.models.property.SystemConfigProperty; import dev.sheldan.abstracto.core.models.AServerChannelUserId; import dev.sheldan.abstracto.core.models.database.AChannel; @@ -13,7 +16,6 @@ import dev.sheldan.abstracto.core.service.management.UserInServerManagementServi import dev.sheldan.abstracto.core.templating.service.TemplateService; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -64,8 +66,8 @@ public class SystemConfigSetupStep extends AbstractConfigSetupStep { AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(user.getGuildId(), user.getUserId()); log.debug("Executing setup for system config {} in server {} for user {}.", systemConfigStepParameter.getConfigKey(), user.getGuildId(), user.getUserId()); - Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId()); - Consumer configAction = (MessageReceivedEvent event) -> { + Consumer finalAction = super.getTimeoutConsumer(user.getGuildId(), user.getChannelId()); + Consumer configAction = (MessageReceivedModel event) -> { try { SetupStepResult result; Message message = event.getMessage(); @@ -88,7 +90,12 @@ public class SystemConfigSetupStep extends AbstractConfigSetupStep { .value(config) .build(); log.debug("Setup for system config {} in server {} for user {} completed. Storing delayed action.", systemConfigStepParameter.getConfigKey(), user.getGuildId(), user.getUserId()); - List delayedSteps = Arrays.asList(build); + DelayedActionConfigContainer container = DelayedActionConfigContainer + .builder() + .type(build.getClass()) + .object(build) + .build(); + List delayedSteps = Arrays.asList(container); result = SetupStepResult .builder() .result(SetupStepResultType.SUCCESS) @@ -101,7 +108,7 @@ public class SystemConfigSetupStep extends AbstractConfigSetupStep { future.completeExceptionally(new SetupStepException(e)); } }; - interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel, parameter.getPreviousMessageId(), configAction, finalAction); + interactiveService.createMessageWithResponse(messageText, aUserInAServer, channel, configAction, finalAction); return future; } @@ -120,7 +127,7 @@ public class SystemConfigSetupStep extends AbstractConfigSetupStep { } @Transactional - public AConfig checkValidity(SystemConfigStepParameter systemConfigStepParameter, MessageReceivedEvent event) { + public AConfig checkValidity(SystemConfigStepParameter systemConfigStepParameter, MessageReceivedModel event) { return configService.getFakeConfigForValue(systemConfigStepParameter.getConfigKey(), event.getMessage().getContentRaw()); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageContextCommandFeatureActivationListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageContextCommandFeatureActivationListener.java new file mode 100644 index 000000000..5be9cf584 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageContextCommandFeatureActivationListener.java @@ -0,0 +1,50 @@ +package dev.sheldan.abstracto.core.listener; + +import dev.sheldan.abstracto.core.listener.async.MessageContextCommandListener; +import dev.sheldan.abstracto.core.listener.async.entity.FeatureActivationListener; +import dev.sheldan.abstracto.core.listener.sync.jda.MessageContextCommandListenerBean; +import dev.sheldan.abstracto.core.models.listener.FeatureActivationListenerModel; +import dev.sheldan.abstracto.core.service.ContextCommandService; +import dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.core.service.GuildService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Guild; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Slf4j +public class MessageContextCommandFeatureActivationListener implements FeatureActivationListener { + + @Autowired + private MessageContextCommandListenerBean listenerBean; + + @Autowired + private FeatureModeService featureModeService; + + @Autowired + private ContextCommandService contextCommandService; + + @Autowired + private GuildService guildService; + + @Override + public DefaultListenerResult execute(FeatureActivationListenerModel model) { + List listeners = listenerBean.getListenerList(); + if(listeners == null || listeners.isEmpty()) { + return DefaultListenerResult.IGNORED; + } + Guild guild = guildService.getGuildById(model.getServerId()); + listeners.forEach(messageContextCommandListener -> { + if(featureModeService.necessaryFeatureModesMet(messageContextCommandListener, model.getServerId())) { + String contextCommandName = messageContextCommandListener.getConfig().getName(); + log.info("Adding message context command {} in guild {}.", contextCommandName, model.getServerId()); + contextCommandService.upsertGuildMessageContextCommand(guild, contextCommandName) + .thenAccept(command -> log.info("Created message context command {} in guild {} because feature {} was enabled.", contextCommandName, guild.getIdLong(), model.getFeatureName())); + } + }); + return DefaultListenerResult.PROCESSED; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageContextCommandFeatureDeactivationListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageContextCommandFeatureDeactivationListener.java new file mode 100644 index 000000000..6f996a480 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/MessageContextCommandFeatureDeactivationListener.java @@ -0,0 +1,52 @@ +package dev.sheldan.abstracto.core.listener; + +import dev.sheldan.abstracto.core.listener.async.MessageContextCommandListener; +import dev.sheldan.abstracto.core.listener.async.entity.FeatureActivationListener; +import dev.sheldan.abstracto.core.listener.async.entity.FeatureDeactivationListener; +import dev.sheldan.abstracto.core.listener.sync.jda.MessageContextCommandListenerBean; +import dev.sheldan.abstracto.core.models.listener.FeatureActivationListenerModel; +import dev.sheldan.abstracto.core.models.listener.FeatureDeactivationListenerModel; +import dev.sheldan.abstracto.core.service.ContextCommandService; +import dev.sheldan.abstracto.core.service.FeatureModeService; +import dev.sheldan.abstracto.core.service.GuildService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Guild; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Slf4j +public class MessageContextCommandFeatureDeactivationListener implements FeatureDeactivationListener { + + @Autowired + private MessageContextCommandListenerBean listenerBean; + + @Autowired + private FeatureModeService featureModeService; + + @Autowired + private ContextCommandService contextCommandService; + + @Autowired + private GuildService guildService; + + @Override + public DefaultListenerResult execute(FeatureDeactivationListenerModel model) { + List listeners = listenerBean.getListenerList(); + if(listeners == null || listeners.isEmpty()) { + return DefaultListenerResult.IGNORED; + } + Guild guild = guildService.getGuildById(model.getServerId()); + listeners.forEach(messageContextCommandListener -> { + if(featureModeService.necessaryFeatureModesMet(messageContextCommandListener, model.getServerId())) { + String contextCommandName = messageContextCommandListener.getConfig().getName(); + log.info("Adding message context command {} in guild {}.", contextCommandName, model.getServerId()); + contextCommandService.deleteGuildContextCommandByName(guild, contextCommandName) + .thenAccept(unused -> log.info("Deleted command {} because feature {} was disabled in guild {}.", contextCommandName, model.getFeatureName(), guild.getIdLong())); + } + }); + return DefaultListenerResult.PROCESSED; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/PaginatorButtonListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/PaginatorButtonListener.java index 1c10acc70..8cd72441c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/PaginatorButtonListener.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/PaginatorButtonListener.java @@ -87,7 +87,7 @@ public class PaginatorButtonListener implements ButtonClickedListener { @Override public Boolean handlesEvent(ButtonClickedListenerModel model) { - return PaginatorServiceBean.PAGINATOR_BUTTON.equals(model.getOrigin()); + return PaginatorServiceBean.PAGINATOR_BUTTON.equals(model.getOrigin()) && model.getEvent().isFromGuild(); } @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncAChannelCreatedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncAChannelCreatedListenerBean.java index a8a6c0a50..7511675f4 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncAChannelCreatedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncAChannelCreatedListenerBean.java @@ -7,8 +7,9 @@ import dev.sheldan.abstracto.core.models.listener.AChannelCreatedListenerModel; import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.service.management.ServerManagementService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.events.channel.text.TextChannelCreateEvent; +import net.dv8tion.jda.api.entities.Channel; +import net.dv8tion.jda.api.entities.GuildChannel; +import net.dv8tion.jda.api.events.channel.ChannelCreateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; @@ -45,17 +46,21 @@ public class AsyncAChannelCreatedListenerBean extends ListenerAdapter { private AsyncAChannelCreatedListenerBean self; @Override - public void onTextChannelCreate(@Nonnull TextChannelCreateEvent event) { + public void onChannelCreate(@Nonnull ChannelCreateEvent event) { self.createChannelInDatabase(event); } @Transactional - public void createChannelInDatabase(@NotNull TextChannelCreateEvent event) { + public void createChannelInDatabase(@NotNull ChannelCreateEvent event) { log.info("Creating text channel with ID {}.", event.getChannel().getIdLong()); - AServer serverObject = serverManagementService.loadOrCreate(event.getChannel().getGuild().getIdLong()); - TextChannel createdChannel = event.getChannel(); - AChannelType type = AChannelType.getAChannelType(createdChannel.getType()); - channelManagementService.createChannel(createdChannel.getIdLong(), type, serverObject); + if(event.getChannel() instanceof GuildChannel) { + AServer serverObject = serverManagementService.loadOrCreate(((GuildChannel)event.getChannel()).getGuild().getIdLong()); + Channel createdChannel = event.getChannel(); + AChannelType type = AChannelType.getAChannelType(createdChannel.getType()); + channelManagementService.createChannel(createdChannel.getIdLong(), type, serverObject); + } else { + log.info("Guild independent channel created - doing nothing."); + } } @TransactionalEventListener diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncAChannelDeletedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncAChannelDeletedListenerBean.java index 799541488..e2130b1d2 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncAChannelDeletedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncAChannelDeletedListenerBean.java @@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.listener.ListenerService; import dev.sheldan.abstracto.core.models.listener.AChannelDeletedListenerModel; import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.channel.text.TextChannelDeleteEvent; +import net.dv8tion.jda.api.events.channel.ChannelDeleteEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -37,12 +37,12 @@ public class AsyncAChannelDeletedListenerBean extends ListenerAdapter { private AsyncAChannelDeletedListenerBean self; @Override - public void onTextChannelDelete(@Nonnull TextChannelDeleteEvent event) { + public void onChannelDelete(@Nonnull ChannelDeleteEvent event) { self.deleteChannelInDb(event); } @Transactional - public void deleteChannelInDb(TextChannelDeleteEvent event) { + public void deleteChannelInDb(ChannelDeleteEvent event) { channelManagementService.markAsDeleted(event.getChannel().getIdLong()); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureActivationListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureActivationListenerBean.java new file mode 100644 index 000000000..efd5f366e --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureActivationListenerBean.java @@ -0,0 +1,32 @@ +package dev.sheldan.abstracto.core.listener.async.entity; + +import dev.sheldan.abstracto.core.listener.ListenerService; +import dev.sheldan.abstracto.core.models.listener.FeatureActivationListenerModel; +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.event.TransactionalEventListener; + +import java.util.List; + +@Component +public class FeatureActivationListenerBean { + @Autowired(required = false) + private List listener; + + @Autowired + private ListenerService listenerService; + + @Autowired + @Qualifier("featureActivationExecutor") + private TaskExecutor featureActivationExecutor; + + @TransactionalEventListener + public void executeListener(FeatureActivationListenerModel activatedFeature){ + if(listener == null) return; + listener.forEach(featureActivatedListener -> + listenerService.executeListener(featureActivatedListener, activatedFeature, featureActivationExecutor) + ); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureDeactivationListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureDeactivationListenerBean.java new file mode 100644 index 000000000..a9e0b6f6b --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureDeactivationListenerBean.java @@ -0,0 +1,32 @@ +package dev.sheldan.abstracto.core.listener.async.entity; + +import dev.sheldan.abstracto.core.listener.ListenerService; +import dev.sheldan.abstracto.core.models.listener.FeatureDeactivationListenerModel; +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.event.TransactionalEventListener; + +import java.util.List; + +@Component +public class FeatureDeactivationListenerBean { + @Autowired(required = false) + private List listener; + + @Autowired + private ListenerService listenerService; + + @Autowired + @Qualifier("featureActivationExecutor") + private TaskExecutor featureDeactivationExecutor; + + @TransactionalEventListener + public void executeListener(FeatureDeactivationListenerModel deactivatedFeature){ + if(listener == null) return; + listener.forEach(featureActivatedListener -> + listenerService.executeListener(featureActivatedListener, deactivatedFeature, featureDeactivationExecutor) + ); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageDeletedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageDeletedListenerBean.java index e9098b9f4..861f0583e 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageDeletedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageDeletedListenerBean.java @@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.listener.MessageDeletedModel; import dev.sheldan.abstracto.core.service.MessageCache; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.message.guild.GuildMessageDeleteEvent; +import net.dv8tion.jda.api.events.message.MessageDeleteEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -35,7 +35,7 @@ public class AsyncMessageDeletedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageDelete(@Nonnull GuildMessageDeleteEvent event) { + public void onMessageDelete(@Nonnull MessageDeleteEvent event) { if(listenerList == null) return; Consumer cachedMessageConsumer = cachedMessage -> { MessageDeletedModel model = getModel(cachedMessage); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageEmbeddedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageEmbeddedListenerBean.java index 770a949ef..82cac1375 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageEmbeddedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageEmbeddedListenerBean.java @@ -3,7 +3,7 @@ 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.guild.GuildMessageEmbedEvent; +import net.dv8tion.jda.api.events.message.MessageEmbedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; @@ -33,13 +33,13 @@ public class AsyncMessageEmbeddedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageEmbed(@NotNull GuildMessageEmbedEvent event) { + public void onMessageEmbed(@NotNull MessageEmbedEvent event) { if(listenerList == null) return; GuildMessageEmbedEventModel model = getModel(event); listenerList.forEach(leaveListener -> listenerService.executeFeatureAwareListener(leaveListener, model, messageEmbeddedListener)); } - private GuildMessageEmbedEventModel getModel(GuildMessageEmbedEvent event) { + private GuildMessageEmbedEventModel getModel(MessageEmbedEvent event) { return GuildMessageEmbedEventModel .builder() .channelId(event.getChannel().getIdLong()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageReceivedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageReceivedListenerBean.java index 28dbb5a90..13754e693 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageReceivedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncMessageReceivedListenerBean.java @@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.service.FeatureConfigService; import dev.sheldan.abstracto.core.service.FeatureFlagService; import dev.sheldan.abstracto.core.service.MessageCache; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -49,14 +49,15 @@ public class AsyncMessageReceivedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) { + public void onMessageReceived(@Nonnull MessageReceivedEvent event) { if(listenerList == null) return; + if(!event.isFromGuild()) return; messageCache.putMessageInCache(event.getMessage()); MessageReceivedModel model = getModel(event); listenerList.forEach(leaveListener -> listenerService.executeFeatureAwareListener(leaveListener, model, messageReceivedExecutor)); } - private MessageReceivedModel getModel(GuildMessageReceivedEvent event) { + private MessageReceivedModel getModel(MessageReceivedEvent event) { return MessageReceivedModel .builder() .message(event.getMessage()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncPrivateMessageReceivedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncPrivateMessageReceivedListenerBean.java index 814808678..f7061cb2f 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncPrivateMessageReceivedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncPrivateMessageReceivedListenerBean.java @@ -5,7 +5,8 @@ import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.CacheEntityService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -44,7 +45,8 @@ public class AsyncPrivateMessageReceivedListenerBean extends ListenerAdapter { @Override @Transactional - public void onPrivateMessageReceived(@Nonnull PrivateMessageReceivedEvent event) { + public void onMessageReceived(@Nonnull MessageReceivedEvent event) { + if(!event.isFromType(ChannelType.PRIVATE)) return; if(privateMessageReceivedListeners == null) return; if(event.getAuthor().getId().equals(botService.getInstance().getSelfUser().getId())) { return; @@ -61,7 +63,7 @@ public class AsyncPrivateMessageReceivedListenerBean extends ListenerAdapter { } @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE) - public void executeIndividualPrivateMessageReceivedListener(CachedMessage cachedMessage, AsyncPrivateMessageReceivedListener messageReceivedListener, PrivateMessageReceivedEvent event) { + public void executeIndividualPrivateMessageReceivedListener(CachedMessage cachedMessage, AsyncPrivateMessageReceivedListener messageReceivedListener, MessageReceivedEvent event) { try { log.debug("Executing private message listener {} for member {}.", messageReceivedListener.getClass().getName(), cachedMessage.getAuthor().getAuthorId()); messageReceivedListener.execute(cachedMessage); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionAddedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionAddedListenerBean.java index 50c1448f4..dede4974c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionAddedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionAddedListenerBean.java @@ -9,7 +9,7 @@ import dev.sheldan.abstracto.core.service.*; import dev.sheldan.abstracto.core.utils.FutureUtils; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -51,7 +51,7 @@ public class AsyncReactionAddedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageReactionAdd(@Nonnull GuildMessageReactionAddEvent event) { + public void onMessageReactionAdd(@Nonnull MessageReactionAddEvent event) { if(listenerList == null) return; if(event.getUserIdLong() == event.getJDA().getSelfUser().getIdLong()) { return; @@ -86,7 +86,7 @@ public class AsyncReactionAddedListenerBean extends ListenerAdapter { } @Transactional - public void callAddedListeners(GuildMessageReactionAddEvent event, CachedMessage cachedMessage, CachedReactions reaction, Member member) { + public void callAddedListeners(MessageReactionAddEvent event, CachedMessage cachedMessage, CachedReactions reaction, Member member) { ServerUser serverUser = ServerUser.builder().serverId(event.getGuild().getIdLong()).userId(event.getUserIdLong()).build(); addReactionIfNotThere(cachedMessage, reaction, serverUser); ReactionAddedModel model = getModel(event, cachedMessage, serverUser, member); @@ -94,7 +94,7 @@ public class AsyncReactionAddedListenerBean extends ListenerAdapter { listenerList.forEach(asyncReactionAddedListener -> listenerService.executeFeatureAwareListener(asyncReactionAddedListener, model, reactionAddedTaskExecutor)); } - private ReactionAddedModel getModel(GuildMessageReactionAddEvent event, CachedMessage cachedMessage, ServerUser userReacting, Member member) { + private ReactionAddedModel getModel(MessageReactionAddEvent event, CachedMessage cachedMessage, ServerUser userReacting, Member member) { return ReactionAddedModel .builder() .reaction(event.getReaction()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionClearedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionClearedListenerBean.java index 2e8bee5b8..a7e99036d 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionClearedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionClearedListenerBean.java @@ -5,7 +5,7 @@ import dev.sheldan.abstracto.core.models.cache.CachedMessage; import dev.sheldan.abstracto.core.models.listener.ReactionClearedModel; import dev.sheldan.abstracto.core.service.MessageCache; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveAllEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveAllEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -36,7 +36,7 @@ public class AsyncReactionClearedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageReactionRemoveAll(@Nonnull GuildMessageReactionRemoveAllEvent event) { + public void onMessageReactionRemoveAll(@Nonnull MessageReactionRemoveAllEvent event) { CompletableFuture asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong()); asyncMessageFromCache.thenAccept(cachedMessage -> { cachedMessage.getReactions().clear(); @@ -52,7 +52,7 @@ public class AsyncReactionClearedListenerBean extends ListenerAdapter { }); } - private ReactionClearedModel getModel(GuildMessageReactionRemoveAllEvent event, CachedMessage message) { + private ReactionClearedModel getModel(MessageReactionRemoveAllEvent event, CachedMessage message) { return ReactionClearedModel .builder() .message(message) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionRemovedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionRemovedListenerBean.java index ef014dfe5..414bec6e4 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionRemovedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncReactionRemovedListenerBean.java @@ -8,7 +8,7 @@ import dev.sheldan.abstracto.core.models.listener.ReactionRemovedModel; import dev.sheldan.abstracto.core.service.*; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -61,7 +61,7 @@ public class AsyncReactionRemovedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageReactionRemove(@Nonnull GuildMessageReactionRemoveEvent event) { + public void onMessageReactionRemove(@Nonnull MessageReactionRemoveEvent event) { if(reactionRemovedListeners == null) return; if(event.getUserIdLong() == botService.getInstance().getSelfUser().getIdLong()) { return; @@ -82,14 +82,14 @@ public class AsyncReactionRemovedListenerBean extends ListenerAdapter { } @Transactional - public void callRemoveListeners(GuildMessageReactionRemoveEvent event, CachedMessage cachedMessage, CachedReactions reaction) { + public void callRemoveListeners(MessageReactionRemoveEvent event, CachedMessage cachedMessage, CachedReactions reaction) { ServerUser serverUser = ServerUser.builder().serverId(cachedMessage.getServerId()).userId(event.getUserIdLong()).build(); removeReactionIfThere(cachedMessage, reaction, serverUser); ReactionRemovedModel model = getModel(event, cachedMessage, serverUser); reactionRemovedListeners.forEach(asyncReactionRemovedListener -> listenerServiceBean.executeFeatureAwareListener(asyncReactionRemovedListener, model, reactionRemovedExecutor)); } - private ReactionRemovedModel getModel(GuildMessageReactionRemoveEvent event, CachedMessage cachedMessage, ServerUser userRemoving) { + private ReactionRemovedModel getModel(MessageReactionRemoveEvent event, CachedMessage cachedMessage, ServerUser userRemoving) { return ReactionRemovedModel .builder() .memberRemoving(event.getMember()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncTextChannelCreatedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncTextChannelCreatedListenerBean.java index f1760aabc..08f16555b 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncTextChannelCreatedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncTextChannelCreatedListenerBean.java @@ -3,7 +3,7 @@ package dev.sheldan.abstracto.core.listener.async.jda; import dev.sheldan.abstracto.core.listener.ListenerService; import dev.sheldan.abstracto.core.models.listener.TextChannelCreatedModel; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.channel.text.TextChannelCreateEvent; +import net.dv8tion.jda.api.events.channel.ChannelCreateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -28,13 +28,13 @@ public class AsyncTextChannelCreatedListenerBean extends ListenerAdapter { private TaskExecutor channelCreatedExecutor; @Override - public void onTextChannelCreate(@Nonnull TextChannelCreateEvent event) { + public void onChannelCreate(@Nonnull ChannelCreateEvent event) { if(listenerList == null) return; TextChannelCreatedModel model = getModel(event); listenerList.forEach(textChannelCreatedListener -> listenerService.executeFeatureAwareListener(textChannelCreatedListener, model, channelCreatedExecutor)); } - private TextChannelCreatedModel getModel(TextChannelCreateEvent event) { + private TextChannelCreatedModel getModel(ChannelCreateEvent event) { return TextChannelCreatedModel .builder() .channel(event.getChannel()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncTextChannelDeletedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncTextChannelDeletedListenerBean.java index 4ff3dee84..6f165a4eb 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncTextChannelDeletedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/jda/AsyncTextChannelDeletedListenerBean.java @@ -3,7 +3,7 @@ package dev.sheldan.abstracto.core.listener.async.jda; import dev.sheldan.abstracto.core.listener.ListenerService; import dev.sheldan.abstracto.core.models.listener.TextChannelDeletedModel; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.channel.text.TextChannelDeleteEvent; +import net.dv8tion.jda.api.events.channel.ChannelDeleteEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -29,13 +29,13 @@ public class AsyncTextChannelDeletedListenerBean extends ListenerAdapter { @Override - public void onTextChannelDelete(@Nonnull TextChannelDeleteEvent event) { + public void onChannelDelete(@Nonnull ChannelDeleteEvent event) { if(listenerList == null) return; TextChannelDeletedModel model = getModel(event); listenerList.forEach(textChannelCreatedListener -> listenerService.executeFeatureAwareListener(textChannelCreatedListener, model, channelDeletedExecutor)); } - private TextChannelDeletedModel getModel(TextChannelDeleteEvent event) { + private TextChannelDeletedModel getModel(ChannelDeleteEvent event) { return TextChannelDeletedModel .builder() .channel(event.getChannel()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/combo/MessageUpdatedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/combo/MessageUpdatedListenerBean.java index 6c8b3d37f..444739943 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/combo/MessageUpdatedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/combo/MessageUpdatedListenerBean.java @@ -14,7 +14,7 @@ import dev.sheldan.abstracto.core.service.MessageCache; import dev.sheldan.abstracto.core.utils.BeanUtils; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent; +import net.dv8tion.jda.api.events.message.MessageUpdateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.apache.commons.lang3.SerializationUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -58,9 +58,6 @@ public class MessageUpdatedListenerBean extends ListenerAdapter { @Autowired private MetricService metricService; - @Autowired - private CacheEntityService cacheEntityService; - private static final CounterMetric MESSAGE_UPDATED_COUNTER = CounterMetric .builder() .name(MESSAGE_METRIC) @@ -69,10 +66,10 @@ public class MessageUpdatedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageUpdate(@Nonnull GuildMessageUpdateEvent event) { + public void onMessageUpdate(@Nonnull MessageUpdateEvent event) { metricService.incrementCounter(MESSAGE_UPDATED_COUNTER); Message message = event.getMessage(); - messageCache.getMessageFromCache(message.getGuild().getIdLong(), message.getTextChannel().getIdLong(), event.getMessageIdLong()).thenAccept(cachedMessage -> { + messageCache.getMessageFromCache(message.getGuild().getIdLong(), message.getChannel().getIdLong(), event.getMessageIdLong()).thenAccept(cachedMessage -> { try { // we need to provide a copy of the object, so modifications here dont influence the async execution // because we do modify it, as we are the one responsible for caching it @@ -94,13 +91,13 @@ public class MessageUpdatedListenerBean extends ListenerAdapter { } @Transactional - public void executeListener(CachedMessage cachedMessage, GuildMessageUpdateEvent event) { + public void executeListener(CachedMessage cachedMessage, MessageUpdateEvent event) { if(listenerList == null) return; MessageUpdatedModel model = getModel(event, cachedMessage); listenerList.forEach(messageUpdatedListener -> listenerService.executeFeatureAwareListener(messageUpdatedListener, model)); } - private MessageUpdatedModel getModel(GuildMessageUpdateEvent event, CachedMessage oldMessage) { + private MessageUpdatedModel getModel(MessageUpdateEvent event, CachedMessage oldMessage) { return MessageUpdatedModel .builder() .after(event.getMessage()) @@ -108,7 +105,7 @@ public class MessageUpdatedListenerBean extends ListenerAdapter { .build(); } - private void executeAsyncListeners(GuildMessageUpdateEvent event, CachedMessage oldMessage) { + private void executeAsyncListeners(MessageUpdateEvent event, CachedMessage oldMessage) { if(asyncListenerList == null) return; MessageUpdatedModel model = getModel(event, oldMessage); asyncListenerList.forEach(messageTextUpdatedListener -> diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageContextCommandListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageContextCommandListenerBean.java new file mode 100644 index 000000000..20baf5854 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageContextCommandListenerBean.java @@ -0,0 +1,94 @@ +package dev.sheldan.abstracto.core.listener.sync.jda; + +import dev.sheldan.abstracto.core.config.FeatureConfig; +import dev.sheldan.abstracto.core.listener.async.MessageContextCommandListener; +import dev.sheldan.abstracto.core.models.listener.interaction.MessageContextInteractionModel; +import dev.sheldan.abstracto.core.service.FeatureConfigService; +import dev.sheldan.abstracto.core.service.FeatureFlagService; +import dev.sheldan.abstracto.core.service.FeatureModeService; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; +import net.dv8tion.jda.api.hooks.ListenerAdapter; +import org.jetbrains.annotations.NotNull; +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 java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class MessageContextCommandListenerBean extends ListenerAdapter { + + @Autowired(required = false) + private List listenerList; + + @Autowired + @Qualifier("messageContextCommandExecutor") + private TaskExecutor messageContextCommandExecutor; + + @Autowired + private MessageContextCommandListenerBean self; + + @Autowired + private FeatureConfigService featureConfigService; + + @Autowired + private FeatureFlagService featureFlagService; + + @Autowired + private FeatureModeService featureModeService; + + @Override + public void onMessageContextInteraction(@NotNull MessageContextInteractionEvent event) { + if(listenerList == null) return; + CompletableFuture.runAsync(() -> self.executeListenerLogic(event), messageContextCommandExecutor).exceptionally(throwable -> { + log.error("Failed to execute listener logic in async button event.", throwable); + return null; + }); + } + + @Transactional + public void executeListenerLogic(MessageContextInteractionEvent event) { + MessageContextInteractionModel model = MessageContextInteractionModel + .builder() + .event(event) + .build(); + + List validListener = filterFeatureAwareListener(listenerList, model); + Optional listenerOptional = findListener(validListener, model); + if(listenerOptional.isPresent()) { + MessageContextCommandListener listener = listenerOptional.get(); + listener.execute(model); + } else { + log.info("No listener found for event {}", event.getClass().getSimpleName()); + } + } + + private Optional findListener(List featureAwareListeners, MessageContextInteractionModel model) { + return featureAwareListeners.stream().filter(contextListener -> contextListener.handlesEvent(model)).findFirst(); + } + + private List filterFeatureAwareListener(List featureAwareListeners, MessageContextInteractionModel model) { + return featureAwareListeners.stream().filter(trFeatureAwareListener -> { + FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(trFeatureAwareListener.getFeature()); + if(!model.getEvent().isFromGuild()) { + return true; + } + if (!featureFlagService.isFeatureEnabled(feature, model.getServerId())) { + return false; + } + return featureModeService.necessaryFeatureModesMet(trFeatureAwareListener, model.getServerId()); + }).collect(Collectors.toList()); + } + + public List getListenerList() { + return listenerList; + } + +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageDeletedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageDeletedListenerBean.java index 951bee917..a31dff372 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageDeletedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageDeletedListenerBean.java @@ -9,7 +9,7 @@ import dev.sheldan.abstracto.core.models.listener.MessageDeletedModel; 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.guild.GuildMessageDeleteEvent; +import net.dv8tion.jda.api.events.message.MessageDeleteEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -47,7 +47,7 @@ public class MessageDeletedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageDelete(@Nonnull GuildMessageDeleteEvent event) { + public void onMessageDelete(@Nonnull MessageDeleteEvent event) { metricService.incrementCounter(MESSAGE_DELETED_COUNTER); if(listenerList == null) return; Consumer cachedMessageConsumer = cachedMessage -> { diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageEmbeddedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageEmbeddedListenerBean.java index 94d9b823b..79d3ca8bb 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageEmbeddedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageEmbeddedListenerBean.java @@ -9,7 +9,7 @@ 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.guild.GuildMessageEmbedEvent; +import net.dv8tion.jda.api.events.message.MessageEmbedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; @@ -48,13 +48,13 @@ public class MessageEmbeddedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageEmbed(@NotNull GuildMessageEmbedEvent event) { + public void onMessageEmbed(@NotNull MessageEmbedEvent event) { if(listenerList == null) return; GuildMessageEmbedEventModel model = buildModel(event); listenerList.forEach(messageReceivedListener -> listenerService.executeFeatureAwareListener(messageReceivedListener, model)); } - private GuildMessageEmbedEventModel buildModel(GuildMessageEmbedEvent event) { + private GuildMessageEmbedEventModel buildModel(MessageEmbedEvent event) { return GuildMessageEmbedEventModel .builder() .channelId(event.getChannel().getIdLong()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageReceivedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageReceivedListenerBean.java index b7676cfb1..e1c6ba1fe 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageReceivedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/MessageReceivedListenerBean.java @@ -12,7 +12,7 @@ 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.guild.GuildMessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -61,7 +61,7 @@ public class MessageReceivedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) { + public void onMessageReceived(@Nonnull MessageReceivedEvent event) { metricService.incrementCounter(MESSAGE_RECEIVED_COUNTER); messageCache.putMessageInCache(event.getMessage()); if(listenerList == null) return; @@ -70,7 +70,7 @@ public class MessageReceivedListenerBean extends ListenerAdapter { } - private MessageReceivedModel getModel(GuildMessageReceivedEvent event) { + private MessageReceivedModel getModel(MessageReceivedEvent event) { return MessageReceivedModel .builder() .message(event.getMessage()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/PrivateMessageReceivedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/PrivateMessageReceivedListenerBean.java index 92ded6c69..4cb49321c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/PrivateMessageReceivedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/PrivateMessageReceivedListenerBean.java @@ -4,7 +4,8 @@ import dev.sheldan.abstracto.core.command.service.ExceptionService; import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.utils.BeanUtils; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import net.dv8tion.jda.api.entities.ChannelType; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -34,7 +35,8 @@ public class PrivateMessageReceivedListenerBean extends ListenerAdapter { @Override @Transactional - public void onPrivateMessageReceived(@Nonnull PrivateMessageReceivedEvent event) { + public void onMessageReceived(@Nonnull MessageReceivedEvent event) { + if(!event.isFromType(ChannelType.PRIVATE)) return; if(privateMessageReceivedListeners == null) return; if(event.getAuthor().getId().equals(botService.getInstance().getSelfUser().getId())) { return; @@ -50,7 +52,7 @@ public class PrivateMessageReceivedListenerBean extends ListenerAdapter { } @Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE) - public void executeIndividualPrivateMessageReceivedListener(@Nonnull PrivateMessageReceivedEvent event, PrivateMessageReceivedListener messageReceivedListener) { + public void executeIndividualPrivateMessageReceivedListener(@Nonnull MessageReceivedEvent event, PrivateMessageReceivedListener messageReceivedListener) { // no feature flag check, because we are in no server context log.debug("Executing private message listener {} for member {}.", messageReceivedListener.getClass().getName(), event.getAuthor().getId()); messageReceivedListener.execute(event.getMessage()); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionAddedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionAddedListenerBean.java index 4fd507517..efda1e192 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionAddedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionAddedListenerBean.java @@ -11,7 +11,7 @@ import dev.sheldan.abstracto.core.utils.BeanUtils; import dev.sheldan.abstracto.core.utils.FutureUtils; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionAddEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -57,7 +57,7 @@ public class ReactionAddedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageReactionAdd(@Nonnull GuildMessageReactionAddEvent event) { + public void onMessageReactionAdd(@Nonnull MessageReactionAddEvent event) { if(addedListenerList == null) return; if(event.getUserIdLong() == botService.getInstance().getSelfUser().getIdLong()) { return; @@ -93,14 +93,14 @@ public class ReactionAddedListenerBean extends ListenerAdapter { } @Transactional - public void callAddedListeners(@Nonnull GuildMessageReactionAddEvent event, CachedMessage cachedMessage, CachedReactions reaction, Member member) { + public void callAddedListeners(@Nonnull MessageReactionAddEvent event, CachedMessage cachedMessage, CachedReactions reaction, Member member) { ServerUser serverUser = ServerUser.builder().serverId(cachedMessage.getServerId()).userId(event.getUserIdLong()).build(); addReactionIfNotThere(cachedMessage, reaction, serverUser); ReactionAddedModel model = getModel(event, cachedMessage, serverUser, member); addedListenerList.forEach(reactedAddedListener -> listenerService.executeFeatureAwareListener(reactedAddedListener, model)); } - private ReactionAddedModel getModel(GuildMessageReactionAddEvent event, CachedMessage cachedMessage, ServerUser userReacting, Member member) { + private ReactionAddedModel getModel(MessageReactionAddEvent event, CachedMessage cachedMessage, ServerUser userReacting, Member member) { return ReactionAddedModel .builder() .reaction(event.getReaction()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionClearedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionClearedListenerBean.java index f658070cf..3d5242b66 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionClearedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionClearedListenerBean.java @@ -7,7 +7,7 @@ import dev.sheldan.abstracto.core.service.*; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.utils.BeanUtils; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveAllEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveAllEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -49,7 +49,7 @@ public class ReactionClearedListenerBean extends ListenerAdapter { @Autowired private ListenerService listenerService; - public void callClearListeners(@Nonnull GuildMessageReactionRemoveAllEvent event, CachedMessage cachedMessage) { + public void callClearListeners(@Nonnull MessageReactionRemoveAllEvent event, CachedMessage cachedMessage) { if(clearedListenerList == null) return; ReactionClearedModel model = getModel(event, cachedMessage); clearedListenerList.forEach(reactionRemovedListener -> @@ -57,7 +57,7 @@ public class ReactionClearedListenerBean extends ListenerAdapter { ); } - private ReactionClearedModel getModel(GuildMessageReactionRemoveAllEvent event, CachedMessage message) { + private ReactionClearedModel getModel(MessageReactionRemoveAllEvent event, CachedMessage message) { return ReactionClearedModel .builder() .message(message) @@ -67,7 +67,7 @@ public class ReactionClearedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageReactionRemoveAll(@Nonnull GuildMessageReactionRemoveAllEvent event) { + public void onMessageReactionRemoveAll(@Nonnull MessageReactionRemoveAllEvent event) { CompletableFuture asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong()); asyncMessageFromCache.thenAccept(cachedMessage -> { cachedMessage.getReactions().clear(); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionRemovedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionRemovedListenerBean.java index f4ef92c90..ed5026245 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionRemovedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReactionRemovedListenerBean.java @@ -9,7 +9,7 @@ import dev.sheldan.abstracto.core.service.*; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.utils.BeanUtils; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemoveEvent; +import net.dv8tion.jda.api.events.message.react.MessageReactionRemoveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -65,7 +65,7 @@ public class ReactionRemovedListenerBean extends ListenerAdapter { @Override @Transactional - public void onGuildMessageReactionRemove(@Nonnull GuildMessageReactionRemoveEvent event) { + public void onMessageReactionRemove(@Nonnull MessageReactionRemoveEvent event) { if(reactionRemovedListeners == null) return; if(event.getUserIdLong() == botService.getInstance().getSelfUser().getIdLong()) { return; @@ -86,14 +86,14 @@ public class ReactionRemovedListenerBean extends ListenerAdapter { } @Transactional - public void callRemoveListeners(@Nonnull GuildMessageReactionRemoveEvent event, CachedMessage cachedMessage, CachedReactions reaction) { + public void callRemoveListeners(@Nonnull MessageReactionRemoveEvent event, CachedMessage cachedMessage, CachedReactions reaction) { ServerUser serverUser = ServerUser.builder().serverId(event.getGuild().getIdLong()).userId(event.getUserIdLong()).build(); removeReactionIfThere(cachedMessage, reaction, serverUser); ReactionRemovedModel model = getModel(event, cachedMessage, serverUser); reactionRemovedListeners.forEach(reactionRemovedListener -> listenerService.executeFeatureAwareListener(reactionRemovedListener, model)); } - private ReactionRemovedModel getModel(GuildMessageReactionRemoveEvent event, CachedMessage cachedMessage, ServerUser userRemoving) { + private ReactionRemovedModel getModel(MessageReactionRemoveEvent event, CachedMessage cachedMessage, ServerUser userRemoving) { return ReactionRemovedModel .builder() .memberRemoving(event.getMember()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReadyListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReadyListener.java index 582475965..534d912a1 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReadyListener.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/ReadyListener.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.core.listener.sync.jda; -import com.jagrosh.jdautilities.commons.waiter.EventWaiter; import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.StartupServiceBean; import dev.sheldan.abstracto.scheduling.service.SchedulerService; @@ -24,9 +23,6 @@ public class ReadyListener extends ListenerAdapter { @Autowired private SchedulerService schedulerService; - @Autowired - private EventWaiter eventWaiter; - @Autowired private BotService botService; @@ -35,7 +31,6 @@ public class ReadyListener extends ListenerAdapter { if(synchronize){ startup.synchronize(); } - botService.getInstance().addEventListener(eventWaiter); schedulerService.startScheduler(); } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/SyncButtonClickedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/SyncButtonClickedListenerBean.java index d2deb55d8..01e0f22ec 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/SyncButtonClickedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/SyncButtonClickedListenerBean.java @@ -15,7 +15,7 @@ import dev.sheldan.abstracto.core.service.FeatureModeService; import dev.sheldan.abstracto.core.service.management.ComponentPayloadManagementService; import dev.sheldan.abstracto.core.utils.BeanUtils; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.interaction.ButtonClickEvent; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; @@ -66,21 +66,17 @@ public class SyncButtonClickedListenerBean extends ListenerAdapter { private Gson gson; @Override - public void onButtonClick(@NotNull ButtonClickEvent event) { + public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { if(listenerList == null) return; - if(event.getGuild() != null) { - event.deferEdit().queue(); - CompletableFuture.runAsync(() -> self.executeListenerLogic(event), buttonClickedExecutor).exceptionally(throwable -> { - log.error("Failed to execute listener logic in async button event.", throwable); - return null; - }); - } else { - log.warn("Received button clicked event outside of guild with id {}.", event.getComponentId()); - } + event.deferEdit().queue(); + CompletableFuture.runAsync(() -> self.executeListenerLogic(event), buttonClickedExecutor).exceptionally(throwable -> { + log.error("Failed to execute listener logic in async button event.", throwable); + return null; + }); } @Transactional - public void executeListenerLogic(@NotNull ButtonClickEvent event) { + public void executeListenerLogic(@NotNull ButtonInteractionEvent event) { ButtonClickedListenerModel model = null; ButtonClickedListener listener = null; try { @@ -104,8 +100,12 @@ public class SyncButtonClickedListenerBean extends ListenerAdapter { log.warn("No callback found for id {}.", event.getComponentId()); } } catch (Exception exception) { - log.error("Button clicked listener failed with exception in server {} and channel {}.", event.getGuild().getIdLong(), - event.getGuildChannel().getIdLong(), exception); + if(event.isFromGuild()) { + log.error("Button clicked listener failed with exception in server {} and channel {}.", event.getGuild().getIdLong(), + event.getGuildChannel().getIdLong(), exception); + } else { + log.error("Button clicked listener failed with exception outside of a guild.", exception); + } if(model != null && listener != null) { InteractionResult result = InteractionResult.fromError("Failed to execute interaction.", exception); if(postInteractionExecutions != null) { @@ -125,6 +125,9 @@ public class SyncButtonClickedListenerBean extends ListenerAdapter { private List filterFeatureAwareListener(List featureAwareListeners, ButtonClickedListenerModel model) { return featureAwareListeners.stream().filter(trFeatureAwareListener -> { FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(trFeatureAwareListener.getFeature()); + if(!model.getEvent().isFromGuild()) { + return true; + } if (!featureFlagService.isFeatureEnabled(feature, model.getServerId())) { return false; } @@ -132,7 +135,7 @@ public class SyncButtonClickedListenerBean extends ListenerAdapter { }).collect(Collectors.toList()); } - private ButtonClickedListenerModel getModel(ButtonClickEvent event, ComponentPayload componentPayload) throws ClassNotFoundException { + private ButtonClickedListenerModel getModel(ButtonInteractionEvent event, ComponentPayload componentPayload) throws ClassNotFoundException { ButtonPayload payload = null; if(componentPayload.getPayloadType() != null && componentPayload.getPayload() != null) { payload = (ButtonPayload) gson.fromJson(componentPayload.getPayload(), Class.forName(componentPayload.getPayloadType())); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/TextChannelCreatedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/TextChannelCreatedListenerBean.java index 42a121b37..6266912c2 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/TextChannelCreatedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/TextChannelCreatedListenerBean.java @@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.listener.ListenerService; import dev.sheldan.abstracto.core.models.listener.TextChannelCreatedModel; import dev.sheldan.abstracto.core.utils.BeanUtils; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.channel.text.TextChannelCreateEvent; +import net.dv8tion.jda.api.events.channel.ChannelCreateEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -24,13 +24,13 @@ public class TextChannelCreatedListenerBean extends ListenerAdapter { private ListenerService listenerService; @Override - public void onTextChannelCreate(@Nonnull TextChannelCreateEvent event) { + public void onChannelCreate(@Nonnull ChannelCreateEvent event) { if(listenerList == null) return; TextChannelCreatedModel model = getModel(event); listenerList.forEach(textChannelCreatedListener -> listenerService.executeFeatureAwareListener(textChannelCreatedListener, model)); } - private TextChannelCreatedModel getModel(TextChannelCreateEvent event) { + private TextChannelCreatedModel getModel(ChannelCreateEvent event) { return TextChannelCreatedModel .builder() .channel(event.getChannel()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/TextChannelDeletedListenerBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/TextChannelDeletedListenerBean.java index 5e17921e6..c0b53f6f6 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/TextChannelDeletedListenerBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/jda/TextChannelDeletedListenerBean.java @@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.listener.ListenerService; import dev.sheldan.abstracto.core.models.listener.TextChannelDeletedModel; import dev.sheldan.abstracto.core.utils.BeanUtils; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.events.channel.text.TextChannelDeleteEvent; +import net.dv8tion.jda.api.events.channel.ChannelDeleteEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -24,13 +24,13 @@ public class TextChannelDeletedListenerBean extends ListenerAdapter { private ListenerService listenerService; @Override - public void onTextChannelDelete(@Nonnull TextChannelDeleteEvent event) { + public void onChannelDelete(@Nonnull ChannelDeleteEvent event) { if(listenerList == null) return; TextChannelDeletedModel model = getModel(event); listenerList.forEach(textChannelCreatedListener -> listenerService.executeFeatureAwareListener(textChannelCreatedListener, model)); } - private TextChannelDeletedModel getModel(TextChannelDeleteEvent event) { + private TextChannelDeletedModel getModel(ChannelDeleteEvent event) { return TextChannelDeletedModel .builder() .channel(event.getChannel()) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ApplicationCommandServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ApplicationCommandServiceBean.java new file mode 100644 index 000000000..eb5d468b5 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ApplicationCommandServiceBean.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.core.service; + +import net.dv8tion.jda.api.entities.Guild; +import org.springframework.stereotype.Component; + +import java.util.concurrent.CompletableFuture; + +@Component +public class ApplicationCommandServiceBean implements ApplicationCommandService { + + @Override + public CompletableFuture deleteGuildCommand(Guild guild, Long commandId) { + return guild.deleteCommandById(commandId).submit(); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java index f2812077d..bfba2f79b 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java @@ -17,6 +17,7 @@ import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementServi import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.service.management.ServerManagementService; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.TextChannel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -189,7 +190,7 @@ public class ChannelGroupServiceBean implements ChannelGroupService { channelGroups.forEach(group -> { List convertedChannels = new ArrayList<>(); group.getChannels().forEach(channel -> { - Optional textChannelInGuild = channelService.getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); + Optional textChannelInGuild = channelService.getGuildMessageChannelFromAChannelOptional(channel); ChannelGroupChannelModel convertedChannel = ChannelGroupChannelModel .builder() .channel(channel) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java index 7bd535790..a3f8a4c9f 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelServiceBean.java @@ -10,12 +10,14 @@ import dev.sheldan.abstracto.core.service.management.ComponentPayloadManagementS import dev.sheldan.abstracto.core.service.management.ServerManagementService; import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.service.TemplateService; +import dev.sheldan.abstracto.core.utils.CompletableFutureList; import dev.sheldan.abstracto.core.utils.FileService; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.interactions.components.ActionComponent; import net.dv8tion.jda.api.interactions.components.ActionRow; -import net.dv8tion.jda.api.requests.RestAction; +import net.dv8tion.jda.api.interactions.components.ItemComponent; import net.dv8tion.jda.api.requests.restaction.MessageAction; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; @@ -28,6 +30,7 @@ import java.io.File; import java.io.IOException; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import static dev.sheldan.abstracto.core.config.MetricConstants.DISCORD_API_INTERACTION_METRIC; import static dev.sheldan.abstracto.core.config.MetricConstants.INTERACTION_TYPE; @@ -103,33 +106,18 @@ public class ChannelServiceBean implements ChannelService { @Override public CompletableFuture sendTextToAChannel(String text, AChannel channel) { - Guild guild = botService.getInstance().getGuildById(channel.getServer().getId()); - if (guild != null) { - TextChannel textChannel = guild.getTextChannelById(channel.getId()); - if(textChannel != null) { - return sendTextToChannel(text, textChannel); - } else { - log.error("Channel {} to post towards was not found in server {}", channel.getId(), channel.getServer().getId()); - throw new ChannelNotInGuildException(channel.getId()); - } - } else { - log.error("Guild {} was not found when trying to post a message", channel.getServer().getId()); - throw new GuildNotFoundException(channel.getServer().getId()); - } + GuildMessageChannel guildMessageChannel = getGuildMessageChannelFromAChannel(channel); + return sendTextToChannel(text, guildMessageChannel); } @Override public CompletableFuture sendMessageToAChannel(Message message, AChannel channel) { - Optional textChannelOpt = getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); - if(textChannelOpt.isPresent()) { - TextChannel textChannel = textChannelOpt.get(); - return sendMessageToChannel(message, textChannel); - } - throw new ChannelNotInGuildException(channel.getId()); + GuildMessageChannel foundChannel = getMessageChannelFromServer(channel.getServer().getId(), channel.getId()); + return sendMessageToChannel(message, foundChannel); } @Override - public CompletableFuture sendMessageToChannel(Message message, MessageChannel channel) { + public CompletableFuture sendMessageToChannel(Message message, GuildMessageChannel channel) { log.debug("Sending message {} from channel {} and server {} to channel {}.", message.getId(), message.getChannel().getId(), message.getGuild().getId(), channel.getId()); metricService.incrementCounter(MESSAGE_SEND_METRIC); @@ -174,11 +162,8 @@ public class ChannelServiceBean implements ChannelService { @Override public List> sendMessageEmbedToSendToAChannel(MessageToSend messageToSend, AChannel channel) { - Optional textChannelFromServer = getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); - if(textChannelFromServer.isPresent()) { - return sendMessageToSendToChannel(messageToSend, textChannelFromServer.get()); - } - throw new ChannelNotInGuildException(channel.getId()); + GuildMessageChannel textChannelFromServer = getMessageChannelFromServer(channel.getServer().getId(), channel.getId()); + return sendMessageToSendToChannel(messageToSend, textChannelFromServer); } @Override @@ -188,7 +173,7 @@ public class ChannelServiceBean implements ChannelService { @Override public CompletableFuture retrieveMessageInChannel(Long serverId, Long channelId, Long messageId) { - TextChannel channel = getTextChannelFromServer(serverId, channelId); + MessageChannel channel = getMessageChannelFromServer(serverId, channelId); return retrieveMessageInChannel(channel, messageId); } @@ -244,8 +229,7 @@ public class ChannelServiceBean implements ChannelService { } List actionRows = messageToSend.getActionRows(); - if(!actionRows.isEmpty() && textChannel instanceof GuildChannel) { - GuildChannel channel = (GuildChannel) textChannel; + if(!actionRows.isEmpty()) { List> groupedActionRows = ListUtils.partition(actionRows, ComponentService.MAX_BUTTONS_PER_ROW); for (int i = 0; i < allMessageActions.size(); i++) { allMessageActions.set(i, allMessageActions.get(i).setActionRows(groupedActionRows.get(i))); @@ -254,14 +238,22 @@ public class ChannelServiceBean implements ChannelService { // TODO maybe possible nicer allMessageActions.add(textChannel.sendMessage(".").setActionRows(groupedActionRows.get(i))); } - AServer server = serverManagementService.loadServer(channel.getGuild()); - actionRows.forEach(components -> components.forEach(component -> { - String id = component.getId(); - MessageToSend.ComponentConfig payload = messageToSend.getComponentPayloads().get(id); - if(payload != null && payload.getPersistCallback()) { - componentPayloadManagementService.createPayload(id, payload.getPayload(), payload.getPayloadType(), payload.getComponentOrigin(), server, payload.getComponentType()); + AServer server = null; + if(textChannel instanceof GuildChannel) { + GuildChannel channel = (GuildChannel) textChannel; + server = serverManagementService.loadServer(channel.getGuild()); + } + for (ActionRow components : actionRows) { + for (ItemComponent component : components) { + if (component instanceof ActionComponent) { + String id = ((ActionComponent) component).getId(); + MessageToSend.ComponentConfig payload = messageToSend.getComponentPayloads().get(id); + if (payload != null && payload.getPersistCallback()) { + componentPayloadManagementService.createPayload(id, payload.getPayload(), payload.getPayloadType(), payload.getComponentOrigin(), server, payload.getComponentType()); + } + } } - })); + } } if(messageToSend.hasFileToSend()) { @@ -292,10 +284,10 @@ public class ChannelServiceBean implements ChannelService { @Override public void editMessageInAChannel(MessageToSend messageToSend, AChannel channel, Long messageId) { - Optional textChannelFromServer = getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); - if(textChannelFromServer.isPresent()) { - TextChannel textChannel = textChannelFromServer.get(); - editMessageInAChannel(messageToSend, textChannel, messageId); + Optional textChannelFromServer = getGuildChannelFromServerOptional(channel.getServer().getId(), channel.getId()); + if(textChannelFromServer.isPresent() && textChannelFromServer.get() instanceof GuildMessageChannel) { + GuildMessageChannel messageChannel = (GuildMessageChannel) textChannelFromServer.get(); + editMessageInAChannel(messageToSend, messageChannel, messageId); } else { throw new ChannelNotInGuildException(channel.getId()); } @@ -406,8 +398,13 @@ public class ChannelServiceBean implements ChannelService { @Override @Transactional - public List> sendEmbedTemplateInTextChannelList(String templateKey, Object model, TextChannel channel) { - MessageToSend messageToSend = templateService.renderEmbedTemplate(templateKey, model, channel.getGuild().getIdLong()); + public List> sendEmbedTemplateInTextChannelList(String templateKey, Object model, MessageChannel channel) { + MessageToSend messageToSend; + if(channel instanceof GuildChannel) { + messageToSend = templateService.renderEmbedTemplate(templateKey, model, ((GuildChannel)channel).getGuild().getIdLong()); + } else { + messageToSend = templateService.renderEmbedTemplate(templateKey, model); + } return sendMessageToSendToChannel(messageToSend, channel); } @@ -419,8 +416,14 @@ public class ChannelServiceBean implements ChannelService { } @Override - public CompletableFuture sendTextTemplateInTextChannel(String templateKey, Object model, TextChannel channel) { - String text = templateService.renderTemplate(templateKey, model, channel.getGuild().getIdLong()); + public CompletableFuture sendTextTemplateInTextChannel(String templateKey, Object model, MessageChannel channel) { + String text; + if(channel instanceof GuildChannel) { + text = templateService.renderTemplate(templateKey, model, ((GuildChannel)channel).getGuild().getIdLong()); + } else { + text = templateService.renderTemplate(templateKey, model); + } + return sendTextToChannel(text, channel); } @@ -432,9 +435,14 @@ public class ChannelServiceBean implements ChannelService { } @Override - public RestAction deleteMessagesInChannel(TextChannel textChannel, List messages) { + public CompletableFuture deleteMessagesInChannel(MessageChannel messageChannel, List messages) { metricService.incrementCounter(CHANNEL_MESSAGE_BULK_DELETE_METRIC); - return textChannel.deleteMessages(messages); + List> deleteFutures = messages + .stream() + .map(ISnowflake::getId) + .map(messageId -> messageChannel.deleteMessageById(messageId).submit()) + .collect(Collectors.toList()); + return new CompletableFutureList<>(deleteFutures).getMainFuture(); } @Override @@ -454,53 +462,115 @@ public class ChannelServiceBean implements ChannelService { } @Override - public Optional getChannelFromAChannel(AChannel channel) { - return getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId()); + public Optional getChannelFromAChannel(AChannel channel) { + return getGuildChannelFromServerOptional(channel.getServer().getId(), channel.getId()); } @Override - public AChannel getFakeChannelFromTextChannel(TextChannel textChannel) { - AServer server = AServer - .builder() - .id(textChannel.getGuild().getIdLong()) - .fake(true) - .build(); + public Optional getGuildMessageChannelFromAChannelOptional(AChannel channel) { + return getMessageChannelFromServerOptional(channel.getServer().getId(), channel.getId()); + } + + @Override + public GuildMessageChannel getGuildMessageChannelFromAChannel(AChannel channel) { + return getMessageChannelFromServer(channel.getServer().getId(), channel.getId()); + } + + @Override + public AChannel getFakeChannelFromTextChannel(MessageChannel messageChannel) { + AServer server = null; + if(messageChannel instanceof GuildChannel) { + server = AServer + .builder() + .id(((GuildChannel) messageChannel).getGuild().getIdLong()) + .fake(true) + .build(); + } return AChannel .builder() .fake(true) - .id(textChannel.getIdLong()) + .id(messageChannel.getIdLong()) .server(server) .build(); } @Override public CompletableFuture sendSimpleTemplateToChannel(Long serverId, Long channelId, String template) { - TextChannel textChannel = getTextChannelFromServer(serverId, channelId); - return sendTextTemplateInTextChannel(template, new Object(), textChannel); + GuildMessageChannel foundChannel = getMessageChannelFromServer(serverId, channelId); + if(foundChannel != null) { + return sendTextTemplateInTextChannel(template, new Object(), foundChannel); + } else { + log.info("Channel {} in server {} not found.", channelId, serverId); + throw new IllegalArgumentException("Incorrect channel type."); + } } @Override - public CompletableFuture getHistoryOfChannel(TextChannel channel, Long startMessageId, Integer amount) { + public CompletableFuture getHistoryOfChannel(MessageChannel channel, Long startMessageId, Integer amount) { return channel.getHistoryBefore(startMessageId, amount).submit(); } @Override - public Optional getTextChannelFromServerOptional(Guild guild, Long textChannelId) { - return Optional.ofNullable(guild.getTextChannelById(textChannelId)); + public Optional getGuildChannelFromServerOptional(Guild guild, Long textChannelId) { + return Optional.ofNullable(guild.getGuildChannelById(textChannelId)); } @Override - public TextChannel getTextChannelFromServer(Guild guild, Long textChannelId) { - return getTextChannelFromServerOptional(guild, textChannelId).orElseThrow(() -> new ChannelNotInGuildException(textChannelId)); + public GuildMessageChannel getMessageChannelFromServer(Guild guild, Long textChannelId) { + GuildChannel foundChannel = getGuildChannelFromServerOptional(guild, textChannelId).orElseThrow(() -> new ChannelNotInGuildException(textChannelId)); + if(foundChannel instanceof GuildMessageChannel) { + return (GuildMessageChannel) foundChannel; + } + log.info("Incorrect channel type of channel {} in guild {}: {}", textChannelId, guild.getId(), foundChannel.getType()); + throw new IllegalArgumentException("Incorrect channel type found."); } @Override - public TextChannel getTextChannelFromServerNullable(Guild guild, Long textChannelId) { - return getTextChannelFromServerOptional(guild, textChannelId).orElse(null); + public GuildMessageChannel getMessageChannelFromServer(Long serverId, Long textChannelId) { + Optional guildOptional = guildService.getGuildByIdOptional(serverId); + if(guildOptional.isPresent()) { + Guild guild = guildOptional.get(); + return getMessageChannelFromServer(guild, textChannelId); + } + throw new GuildNotFoundException(serverId); } @Override - public Optional getTextChannelFromServerOptional(Long serverId, Long textChannelId) { + public Optional getMessageChannelFromServerOptional(Long serverId, Long textChannelId) { + Optional guildChannel = getGuildChannelFromServerOptional(serverId, textChannelId); + if(guildChannel.isPresent() && guildChannel.get() instanceof GuildMessageChannel) { + return Optional.of((GuildMessageChannel)guildChannel.get()); + } + return Optional.empty(); + } + + @Override + public GuildMessageChannel getMessageChannelFromServerNullable(Guild guild, Long textChannelId) { + return getMessageChannelFromServer(guild, textChannelId); + } + + @Override + public Optional getGuildChannelFromServerOptional(Long serverId, Long channelId) { + Optional guildOptional = guildService.getGuildByIdOptional(serverId); + if(guildOptional.isPresent()) { + Guild guild = guildOptional.get(); + return Optional.ofNullable(guild.getGuildChannelById(channelId)); + } + throw new GuildNotFoundException(serverId); + } + + @Override + public GuildChannel getGuildChannelFromServer(Long serverId, Long channelId) { + Optional guildOptional = guildService.getGuildByIdOptional(serverId); + if(guildOptional.isPresent()) { + Guild guild = guildOptional.get(); + return guild.getGuildChannelById(channelId); + } + throw new GuildNotFoundException(serverId); + } + + @Override + public Optional getTextChannelFromServerOptional(Long serverId, Long textChannelId) { Optional guildOptional = guildService.getGuildByIdOptional(serverId); if(guildOptional.isPresent()) { Guild guild = guildOptional.get(); @@ -509,10 +579,6 @@ public class ChannelServiceBean implements ChannelService { throw new GuildNotFoundException(serverId); } - @Override - public TextChannel getTextChannelFromServer(Long serverId, Long textChannelId) { - return getTextChannelFromServerOptional(serverId, textChannelId).orElseThrow(() -> new ChannelNotInGuildException(textChannelId)); - } @Override public CompletableFuture setSlowModeInChannel(TextChannel textChannel, Integer seconds) { @@ -521,17 +587,23 @@ public class ChannelServiceBean implements ChannelService { } @Override - public List> sendFileToChannel(String fileContent, String fileNameTemplate, String messageTemplate, Object model, TextChannel channel) { + public List> sendFileToChannel(String fileContent, String fileNameTemplate, String messageTemplate, Object model, MessageChannel channel) { String fileName = templateService.renderTemplate(fileNameTemplate, model); File tempFile = fileService.createTempFile(fileName); try { fileService.writeContentToFile(tempFile, fileContent); - long maxFileSize = channel.getGuild().getMaxFileSize(); - // in this case, we cannot upload the file, so we need to fail - if(tempFile.length() > maxFileSize) { - throw new UploadFileTooLargeException(tempFile.length(), maxFileSize); + MessageToSend messageToSend; + if(channel instanceof GuildMessageChannel) { + GuildMessageChannel guildChannel = (GuildMessageChannel) channel; + long maxFileSize = guildChannel.getGuild().getMaxFileSize(); + // in this case, we cannot upload the file, so we need to fail + if(tempFile.length() > maxFileSize) { + throw new UploadFileTooLargeException(tempFile.length(), maxFileSize); + } + messageToSend = templateService.renderEmbedTemplate(messageTemplate, model, guildChannel.getGuild().getIdLong()); + } else { + messageToSend = templateService.renderEmbedTemplate(messageTemplate, model); } - MessageToSend messageToSend = templateService.renderEmbedTemplate(messageTemplate, model, channel.getGuild().getIdLong()); messageToSend.setFileToSend(tempFile); return sendMessageToSendToChannel(messageToSend, channel); } catch (IOException e) { @@ -547,14 +619,16 @@ public class ChannelServiceBean implements ChannelService { } @Override - public List> sendFileToChannel(String fileContent, String fileName, TextChannel channel) { + public List> sendFileToChannel(String fileContent, String fileName, MessageChannel channel) { File tempFile = fileService.createTempFile(fileName); try { fileService.writeContentToFile(tempFile, fileContent); - long maxFileSize = channel.getGuild().getMaxFileSize(); - // in this case, we cannot upload the file, so we need to fail - if(tempFile.length() > maxFileSize) { - throw new UploadFileTooLargeException(tempFile.length(), maxFileSize); + if(channel instanceof GuildMessageChannel) { + long maxFileSize = ((GuildMessageChannel) channel).getGuild().getMaxFileSize(); + // in this case, we cannot upload the file, so we need to fail + if(tempFile.length() > maxFileSize) { + throw new UploadFileTooLargeException(tempFile.length(), maxFileSize); + } } MessageToSend messageToSend = MessageToSend .builder() diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ComponentServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ComponentServiceBean.java index 5fcc0e83d..d89ebd60d 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ComponentServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ComponentServiceBean.java @@ -2,16 +2,18 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.models.template.button.ButtonConfigModel; import net.dv8tion.jda.api.entities.Emoji; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.interactions.components.ActionComponent; import net.dv8tion.jda.api.interactions.components.ActionRow; -import net.dv8tion.jda.api.interactions.components.Button; -import net.dv8tion.jda.api.interactions.components.ButtonStyle; +import net.dv8tion.jda.api.interactions.components.buttons.Button; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import org.apache.commons.collections4.ListUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.*; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @@ -35,7 +37,7 @@ public class ComponentServiceBean implements ComponentService { } @Override - public CompletableFuture addButtonToMessage(Long messageId, TextChannel textChannel, String buttonId, String description, String emoteMarkdown, ButtonStyle style) { + public CompletableFuture addButtonToMessage(Long messageId, GuildMessageChannel textChannel, String buttonId, String description, String emoteMarkdown, ButtonStyle style) { return channelService.retrieveMessageInChannel(textChannel, messageId).thenCompose(message -> { Button button = Button.of(style, buttonId, description); if(emoteMarkdown != null) { @@ -83,11 +85,13 @@ public class ComponentServiceBean implements ComponentService { public CompletableFuture removeComponentWithId(Message message, String componentId, Boolean rearrange) { List actionRows = new ArrayList<>(); if(Boolean.TRUE.equals(rearrange)) { - List components = new ArrayList<>(); + List components = new ArrayList<>(); message.getActionRows().forEach(row -> row .getComponents() .stream() + .filter(ActionComponent.class::isInstance) + .map(ActionComponent.class::cast) .filter(component -> component.getId() == null || !component.getId().equals(componentId)) .forEach(components::add)); actionRows = splitIntoActionRowsMax(components); @@ -97,6 +101,8 @@ public class ComponentServiceBean implements ComponentService { row .getComponents() .stream() + .filter(ActionComponent.class::isInstance) + .map(ActionComponent.class::cast) .filter(component -> component.getId() == null || !component.getId().equals(componentId)) .collect(Collectors.toList()))); } @@ -105,8 +111,8 @@ public class ComponentServiceBean implements ComponentService { } @Override - public List splitIntoActionRowsMax(List allComponents) { - List> actionRows = ListUtils.partition(allComponents, MAX_BUTTONS_PER_ROW); + public List splitIntoActionRowsMax(List allComponents) { + List> actionRows = ListUtils.partition(allComponents, MAX_BUTTONS_PER_ROW); return actionRows.stream().map(ActionRow::of).collect(Collectors.toList()); } @@ -118,18 +124,7 @@ public class ComponentServiceBean implements ComponentService { private CompletableFuture setAllButtonStatesTo(Message message, Boolean disabled) { List actionRows = new ArrayList<>(); - message.getActionRows().forEach(row -> { - List newComponents = new ArrayList<>(); - row.getComponents().forEach(component -> { - if(component.getType().equals(net.dv8tion.jda.api.interactions.components.Component.Type.BUTTON)) { - Button button = ((Button) component).withDisabled(disabled); - newComponents.add(button); - } else { - newComponents.add(component); - } - }); - actionRows.add(ActionRow.of(newComponents)); - }); + message.getActionRows().forEach(row -> actionRows.add(row.withDisabled(disabled))); return messageService.editMessageWithActionRows(message, actionRows); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ContextCommandServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ContextCommandServiceBean.java new file mode 100644 index 000000000..5bf243bb5 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ContextCommandServiceBean.java @@ -0,0 +1,36 @@ +package dev.sheldan.abstracto.core.service; + +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.interactions.commands.Command; +import net.dv8tion.jda.api.interactions.commands.build.Commands; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +@Component +public class ContextCommandServiceBean implements ContextCommandService { + + @Autowired + private ApplicationCommandService applicationCommandService; + + @Override + public CompletableFuture upsertGuildMessageContextCommand(Guild guild, String name) { + return guild.upsertCommand(Commands.context(Command.Type.MESSAGE, name)).submit(); + } + + @Override + public CompletableFuture deleteGuildContextCommand(Guild guild, Long commandId) { + return applicationCommandService.deleteGuildCommand(guild, commandId); + } + + @Override + public CompletableFuture deleteGuildContextCommandByName(Guild guild, String commandName) { + return guild.retrieveCommands().submit().thenCompose(commands -> { + Optional foundCommand = commands.stream().filter(command -> command.getType().equals(Command.Type.MESSAGE)).findAny(); + return foundCommand.map(command -> guild.deleteCommandById(command.getIdLong()).submit()) + .orElseGet(() -> CompletableFuture.completedFuture(null)); + }); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureConfigServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureConfigServiceBean.java index ce9e317a2..5adb2ab7f 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureConfigServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureConfigServiceBean.java @@ -7,6 +7,9 @@ import dev.sheldan.abstracto.core.config.PostTargetEnum; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.core.exception.FeatureModeNotFoundException; import dev.sheldan.abstracto.core.exception.FeatureNotFoundException; +import dev.sheldan.abstracto.core.listener.FeatureAwareListener; +import dev.sheldan.abstracto.core.listener.FeatureAwareListenerModel; +import dev.sheldan.abstracto.core.listener.ListenerExecutionResult; import dev.sheldan.abstracto.core.models.FeatureValidationResult; import dev.sheldan.abstracto.core.models.database.AFeature; import dev.sheldan.abstracto.core.models.database.AServer; @@ -29,6 +32,12 @@ public class FeatureConfigServiceBean implements FeatureConfigService { @Autowired private FeatureValidatorService featureValidatorService; + @Autowired + private FeatureFlagService featureFlagService; + + @Autowired + private FeatureModeService featureModeService; + @Override public List getAllFeatures() { return availableFeatures @@ -148,4 +157,16 @@ public class FeatureConfigServiceBean implements FeatureConfigService { .anyMatch(featureMode -> featureMode.getKey().equalsIgnoreCase(modeName)) ); } + + @Override + public boolean isFeatureAwareEnabled(FeatureAwareListener listener, Long serverId) { + FeatureConfig feature = getFeatureDisplayForFeature(listener.getFeature()); + if(serverId == null) { + return true; + } + if (!featureFlagService.isFeatureEnabled(feature, serverId)) { + return false; + } + return featureModeService.necessaryFeatureModesMet(listener, serverId); + } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureFlagServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureFlagServiceBean.java index 2df900e6e..acd86da5c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureFlagServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureFlagServiceBean.java @@ -7,11 +7,14 @@ import dev.sheldan.abstracto.core.exception.FeatureNotFoundException; import dev.sheldan.abstracto.core.models.database.AFeature; import dev.sheldan.abstracto.core.models.database.AFeatureFlag; import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.models.listener.FeatureActivationListenerModel; +import dev.sheldan.abstracto.core.models.listener.FeatureDeactivationListenerModel; import dev.sheldan.abstracto.core.models.property.FeatureFlagProperty; import dev.sheldan.abstracto.core.service.management.DefaultFeatureFlagManagementService; import dev.sheldan.abstracto.core.service.management.FeatureFlagManagementService; import dev.sheldan.abstracto.core.service.management.ServerManagementService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; import java.util.Optional; @@ -34,6 +37,9 @@ public class FeatureFlagServiceBean implements FeatureFlagService { @Autowired private DefaultFeatureFlagManagementService defaultFeatureFlagManagementService; + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + @Override public boolean isFeatureEnabled(FeatureConfig name, Long serverId) { return getFeatureFlagValue(name.getFeature(), serverId); @@ -56,6 +62,12 @@ public class FeatureFlagServiceBean implements FeatureFlagService { if(!featureConfigService.doesFeatureExist(name)) { throw new FeatureNotFoundException(feature.getKey(), featureConfigService.getFeaturesAsList()); } + FeatureActivationListenerModel model = FeatureActivationListenerModel + .builder() + .featureName(feature.getKey()) + .serverId(server.getId()) + .build(); + applicationEventPublisher.publishEvent(model); updateFeatureFlag(feature, server, true); } @@ -71,6 +83,12 @@ public class FeatureFlagServiceBean implements FeatureFlagService { if(!featureConfigService.doesFeatureExist(name)) { throw new FeatureNotFoundException(feature.getKey(), featureConfigService.getFeaturesAsList()); } + FeatureDeactivationListenerModel model = FeatureDeactivationListenerModel + .builder() + .featureName(feature.getKey()) + .serverId(server.getId()) + .build(); + applicationEventPublisher.publishEvent(model); updateFeatureFlag(feature, server, false); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureSetupServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureSetupServiceBean.java index 3a3b90749..e9f301602 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureSetupServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/FeatureSetupServiceBean.java @@ -3,14 +3,16 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.command.service.ExceptionService; import dev.sheldan.abstracto.core.config.FeatureConfig; import dev.sheldan.abstracto.core.config.PostTargetEnum; -import dev.sheldan.abstracto.core.exception.ChannelNotInGuildException; import dev.sheldan.abstracto.core.interactive.*; +import dev.sheldan.abstracto.core.interactive.setup.step.PostTargetSetupStep; +import dev.sheldan.abstracto.core.interactive.setup.step.SetupSummaryStep; +import dev.sheldan.abstracto.core.interactive.setup.step.SystemConfigSetupStep; import dev.sheldan.abstracto.core.models.AServerChannelUserId; import dev.sheldan.abstracto.core.models.template.commands.SetupCompletedNotificationModel; import dev.sheldan.abstracto.core.models.template.commands.SetupInitialMessageModel; import dev.sheldan.abstracto.core.templating.service.TemplateService; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -49,9 +51,6 @@ public class FeatureSetupServiceBean implements FeatureSetupService { @Autowired private MemberService memberService; - @Autowired - private BotService botService; - @Autowired private ExceptionService exceptionService; @@ -59,68 +58,72 @@ public class FeatureSetupServiceBean implements FeatureSetupService { public CompletableFuture performFeatureSetup(FeatureConfig featureConfig, AServerChannelUserId user, Long initialMessageId) { log.info("Performing setup of feature {} for user {} in channel {} in server {}.", featureConfig.getFeature().getKey(), user.getUserId(), user.getChannelId(), user.getGuildId()); - Optional textChannelInGuild = channelService.getTextChannelFromServerOptional(user.getGuildId(), user.getChannelId()); - if (textChannelInGuild.isPresent()) { - Set requiredSystemConfigKeys = new HashSet<>(); - Set requiredPostTargets = new HashSet<>(); - Set customSetupSteps = new HashSet<>(); + GuildMessageChannel messageChannelInGuild = channelService.getMessageChannelFromServer(user.getGuildId(), user.getChannelId()); + Set requiredSystemConfigKeys = new HashSet<>(); + Set requiredPostTargets = new HashSet<>(); + Set customSetupSteps = new HashSet<>(); - collectRequiredFeatureSteps(featureConfig, requiredSystemConfigKeys, requiredPostTargets, customSetupSteps, new HashSet<>()); + collectRequiredFeatureSteps(featureConfig, requiredSystemConfigKeys, requiredPostTargets, customSetupSteps, new HashSet<>()); - List steps = new ArrayList<>(); - requiredSystemConfigKeys.forEach(s -> { - log.debug("Feature requires system config key {}.", s); - SetupExecution execution = SetupExecution - .builder() - .step(systemConfigSetupStep) - .parameter(SystemConfigStepParameter.builder().configKey(s).build()) - .build(); - steps.add(execution); - }); - requiredPostTargets.forEach(postTargetEnum -> { - log.debug("Feature requires post target {}.", postTargetEnum.getKey()); - SetupExecution execution = SetupExecution - .builder() - .step(postTargetSetupStep) - .parameter(PostTargetStepParameter.builder().postTargetKey(postTargetEnum.getKey()).build()) - .build(); - steps.add(execution); - }); - customSetupSteps.forEach(setupStep -> { - log.debug("Feature requires custom setup step {}.", setupStep.getClass().getName()); - SetupExecution execution = SetupExecution - .builder() - .step(setupStep) - .parameter(EmptySetupParameter.builder().build()) - .build(); - steps.add(execution); - }); - for (int i = 0; i < steps.size(); i++) { - SetupExecution setupExecution = steps.get(i); - setupExecution.getParameter().setPreviousMessageId(initialMessageId); - if (i < steps.size() - 1) { - setupExecution.setNextStep(steps.get(i + 1)); - } - } - - SetupInitialMessageModel setupInitialMessageModel = SetupInitialMessageModel + List steps = new ArrayList<>(); + requiredSystemConfigKeys.forEach(s -> { + log.debug("Feature requires system config key {}.", s); + SetupExecution execution = SetupExecution .builder() - .featureConfig(featureConfig) + .step(systemConfigSetupStep) + .parameter(SystemConfigStepParameter.builder().configKey(s).build()) .build(); - TextChannel textChannel = textChannelInGuild.get(); - String text = templateService.renderTemplate(FEATURE_SETUP_INITIAL_MESSAGE_TEMPLATE_KEY, setupInitialMessageModel, user.getGuildId()); - channelService.sendTextToChannel(text, textChannel); - ArrayList delayedActionConfigs = new ArrayList<>(); - featureConfig - .getAutoSetupSteps() - .forEach(autoDelayedAction -> delayedActionConfigs.add(autoDelayedAction.getDelayedActionConfig(user))); - return executeFeatureSetup(featureConfig, steps, user, delayedActionConfigs); + steps.add(execution); + }); + requiredPostTargets.forEach(postTargetEnum -> { + log.debug("Feature requires post target {}.", postTargetEnum.getKey()); + SetupExecution execution = SetupExecution + .builder() + .step(postTargetSetupStep) + .parameter(PostTargetStepParameter.builder().postTargetKey(postTargetEnum.getKey()).build()) + .build(); + steps.add(execution); + }); + customSetupSteps.forEach(setupStep -> { + log.debug("Feature requires custom setup step {}.", setupStep.getClass().getName()); + SetupExecution execution = SetupExecution + .builder() + .step(setupStep) + .parameter(EmptySetupParameter.builder().build()) + .build(); + steps.add(execution); + }); + for (int i = 0; i < steps.size(); i++) { + SetupExecution setupExecution = steps.get(i); + setupExecution.getParameter().setPreviousMessageId(initialMessageId); + if (i < steps.size() - 1) { + setupExecution.setNextStep(steps.get(i + 1)); + } } - throw new ChannelNotInGuildException(user.getChannelId()); + + SetupInitialMessageModel setupInitialMessageModel = SetupInitialMessageModel + .builder() + .featureConfig(featureConfig) + .build(); + String text = templateService.renderTemplate(FEATURE_SETUP_INITIAL_MESSAGE_TEMPLATE_KEY, setupInitialMessageModel, user.getGuildId()); + channelService.sendTextToChannel(text, messageChannelInGuild); + ArrayList delayedActionConfigs = new ArrayList<>(); + featureConfig + .getAutoSetupSteps() + .forEach(autoStep -> { + DelayedActionConfig autoDelayedAction = autoStep.getDelayedActionConfig(user); + DelayedActionConfigContainer container = DelayedActionConfigContainer + .builder() + .object(autoDelayedAction) + .type(autoDelayedAction.getClass()) + .build(); + delayedActionConfigs.add(container); + }); + return executeFeatureSetup(featureConfig, steps, user, delayedActionConfigs); } @Override - public CompletableFuture executeFeatureSetup(FeatureConfig featureConfig, List steps, AServerChannelUserId user, List delayedActionConfigs) { + public CompletableFuture executeFeatureSetup(FeatureConfig featureConfig, List steps, AServerChannelUserId user, List delayedActionConfigs) { if (!steps.isEmpty()) { SetupExecution nextStep = steps.get(0); return executeStep(user, nextStep, delayedActionConfigs, featureConfig); @@ -131,7 +134,7 @@ public class FeatureSetupServiceBean implements FeatureSetupService { } } - private CompletableFuture executeStep(AServerChannelUserId aUserInAServer, SetupExecution execution, List delayedActionConfigs, FeatureConfig featureConfig) { + private CompletableFuture executeStep(AServerChannelUserId aUserInAServer, SetupExecution execution, List delayedActionConfigs, FeatureConfig featureConfig) { log.debug("Executing step {} in server {} in channel {} for user {}.", execution.getStep().getClass(), aUserInAServer.getGuildId(), aUserInAServer.getChannelId(), aUserInAServer.getUserId()); return execution.getStep().execute(aUserInAServer, execution.getParameter()).thenAccept(setpResult -> { if (setpResult.getResult().equals(SetupStepResultType.SUCCESS)) { @@ -158,9 +161,9 @@ public class FeatureSetupServiceBean implements FeatureSetupService { @Transactional public void showExceptionMessage(Throwable throwable, AServerChannelUserId aServerChannelUserId) { - Optional channelOptional = channelService.getTextChannelFromServerOptional(aServerChannelUserId.getGuildId(), aServerChannelUserId.getChannelId()); + GuildMessageChannel messageChannelInGuild = channelService.getMessageChannelFromServer(aServerChannelUserId.getGuildId(), aServerChannelUserId.getChannelId()); memberService.getMemberInServerAsync(aServerChannelUserId.getGuildId(), aServerChannelUserId.getUserId()).thenAccept(member -> - channelOptional.ifPresent(textChannel -> exceptionService.reportExceptionToChannel(throwable, textChannel, member)) + exceptionService.reportExceptionToChannel(throwable, messageChannelInGuild, member) ).exceptionally(innserThrowable -> { log.error("Failed to report exception message for exception {} for user {} in channel {} in server {}.", throwable, aServerChannelUserId.getUserId(), aServerChannelUserId.getChannelId(), aServerChannelUserId.getGuildId(), innserThrowable); return null; @@ -168,43 +171,48 @@ public class FeatureSetupServiceBean implements FeatureSetupService { } @Transactional - public void executePostSetupSteps(List delayedActionConfigs, AServerChannelUserId user, Long initialMessage, FeatureConfig featureConfig) { + public void executePostSetupSteps(List delayedActionConfigs, AServerChannelUserId user, Long initialMessage, FeatureConfig featureConfig) { SetupSummaryStepParameter parameter = SetupSummaryStepParameter .builder() .delayedActionList(delayedActionConfigs) + .featureConfig(featureConfig) .previousMessageId(initialMessage) .build(); - setupSummaryStep.execute(user, parameter).thenAccept(setupStepResult -> self.notifyAboutCompletion(user, featureConfig, setupStepResult)); + setupSummaryStep.execute(user, parameter) + .exceptionally(throwable -> { + showExceptionMessage(throwable.getCause(), user); + return null; + }); } @Transactional - public void notifyAboutCompletion(AServerChannelUserId aServerChannelUserId, FeatureConfig featureConfig, SetupStepResult result) { + public void notifyAboutCompletion(AServerChannelUserId aServerChannelUserId, String featureKey, SetupStepResult result) { log.debug("Notifying user {} in channel {} in server {} about completion of setup for feature {}.", - aServerChannelUserId.getUserId(), aServerChannelUserId.getChannelId(), aServerChannelUserId.getGuildId(), featureConfig.getFeature().getKey()); + aServerChannelUserId.getUserId(), aServerChannelUserId.getChannelId(), aServerChannelUserId.getGuildId(), featureKey); String templateKey; if (result.getResult().equals(SetupStepResultType.CANCELLED)) { templateKey = FEATURE_SETUP_CANCELLATION_NOTIFICATION_TEMPLATE; } else { templateKey = FEATURE_SETUP_COMPLETION_NOTIFICATION_TEMPLATE; } - notifyUserWithTemplate(aServerChannelUserId, featureConfig, templateKey); + notifyUserWithTemplate(aServerChannelUserId, featureKey, templateKey); } - private void notifyUserWithTemplate(AServerChannelUserId aServerChannelUserId, FeatureConfig featureConfig, String templateName) { + private void notifyUserWithTemplate(AServerChannelUserId aServerChannelUserId, String featureKey, String templateName) { SetupCompletedNotificationModel model = SetupCompletedNotificationModel .builder() - .featureConfig(featureConfig) + .featureKey(featureKey) .build(); String text = templateService.renderTemplate(templateName, model, aServerChannelUserId.getGuildId()); - Optional textChannel = channelService.getTextChannelFromServerOptional(aServerChannelUserId.getGuildId(), aServerChannelUserId.getChannelId()); - textChannel.ifPresent(channel -> channelService.sendTextToChannel(text, channel)); + GuildMessageChannel messageChannelInGuild = channelService.getMessageChannelFromServer(aServerChannelUserId.getGuildId(), aServerChannelUserId.getChannelId()); + channelService.sendTextToChannel(text, messageChannelInGuild); } @Transactional public void notifyAboutCancellation(AServerChannelUserId aServerChannelUserId, FeatureConfig featureConfig) { log.debug("Notifying user {} in channel {} in server {} about cancellation of setup for feature {}.", aServerChannelUserId.getUserId(), aServerChannelUserId.getChannelId(), aServerChannelUserId.getGuildId(), featureConfig.getFeature().getKey()); - notifyUserWithTemplate(aServerChannelUserId, featureConfig, FEATURE_SETUP_CANCELLATION_NOTIFICATION_TEMPLATE); + notifyUserWithTemplate(aServerChannelUserId, featureConfig.getFeature().getKey(), FEATURE_SETUP_CANCELLATION_NOTIFICATION_TEMPLATE); } private void collectRequiredFeatureSteps(FeatureConfig featureConfig, Set requiredSystemConfigKeys, diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/InteractionServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/InteractionServiceBean.java index a244a935b..d968b0790 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/InteractionServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/InteractionServiceBean.java @@ -14,6 +14,7 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.interactions.Interaction; import net.dv8tion.jda.api.interactions.InteractionHook; +import net.dv8tion.jda.api.interactions.components.ActionComponent; import net.dv8tion.jda.api.interactions.components.ActionRow; import net.dv8tion.jda.api.requests.restaction.WebhookMessageAction; import org.springframework.beans.factory.annotation.Autowired; @@ -86,10 +87,12 @@ public class InteractionServiceBean implements InteractionService { AServer server = serverManagementService.loadServer(interactionHook.getInteraction().getGuild()); allMessageActions.set(0, allMessageActions.get(0).addActionRows(actionRows)); actionRows.forEach(components -> components.forEach(component -> { - String id = component.getId(); - MessageToSend.ComponentConfig payload = messageToSend.getComponentPayloads().get(id); - if(payload.getPersistCallback()) { - componentPayloadManagementService.createPayload(id, payload.getPayload(), payload.getPayloadType(), payload.getComponentOrigin(), server, payload.getComponentType()); + if(component instanceof ActionComponent) { + String id = ((ActionComponent)component).getId(); + MessageToSend.ComponentConfig payload = messageToSend.getComponentPayloads().get(id); + if(payload.getPersistCallback()) { + componentPayloadManagementService.createPayload(id, payload.getPayload(), payload.getPayloadType(), payload.getComponentOrigin(), server, payload.getComponentType()); + } } })); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MemberServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MemberServiceBean.java index d592ea2f4..1818b32bb 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MemberServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MemberServiceBean.java @@ -8,10 +8,7 @@ import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AUser; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import lombok.extern.slf4j.Slf4j; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.TextChannel; -import net.dv8tion.jda.api.entities.User; +import net.dv8tion.jda.api.entities.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -35,15 +32,10 @@ public class MemberServiceBean implements MemberService { @Override public GuildChannelMember getServerChannelUser(Long serverId, Long channelId, Long userId) { log.debug("Trying to retrieve member {}, channel {} in server {} from cache.", userId, channelId, serverId); + GuildChannel guildChannel = channelService.getGuildChannelFromServer(serverId, channelId); Guild guild = guildService.getGuildById(serverId); - Optional textChannelOptional = channelService.getTextChannelFromServerOptional(guild, channelId); - if(textChannelOptional.isPresent()) { - TextChannel textChannel = textChannelOptional.get(); - Member member = guild.getMemberById(userId); - return GuildChannelMember.builder().guild(guild).textChannel(textChannel).member(member).build(); - } else { - throw new ChannelNotInGuildException(channelId); - } + Member member = guild.getMemberById(userId); + return GuildChannelMember.builder().guild(guild).textChannel(guildChannel).member(member).build(); } @Override @@ -52,9 +44,9 @@ public class MemberServiceBean implements MemberService { CompletableFuture memberFuture = getMemberInServerAsync(serverId, userId); Guild guild = guildService.getGuildById(serverId); - TextChannel textChannel = channelService.getTextChannelFromServer(guild, channelId); + GuildMessageChannel messageChannel = channelService.getMessageChannelFromServer(guild, channelId); return memberFuture.thenApply(member -> - GuildChannelMember.builder().guild(guild).textChannel(textChannel).member(member).build() + GuildChannelMember.builder().guild(guild).textChannel(messageChannel).member(member).build() ); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageCacheBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageCacheBean.java index 3b1facb58..36dc14645 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageCacheBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageCacheBean.java @@ -5,8 +5,9 @@ import dev.sheldan.abstracto.core.exception.GuildNotFoundException; import dev.sheldan.abstracto.core.models.cache.CachedMessage; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.MessageChannel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.CacheEvict; @@ -75,10 +76,10 @@ public class MessageCacheBean implements MessageCache { CompletableFuture future = new CompletableFuture<>(); Optional guildOptional = guildService.getGuildByIdOptional(guildId); if(guildOptional.isPresent()) { - Optional textChannelByIdOptional = channelService.getTextChannelFromServerOptional(guildOptional.get(), textChannelId); + Optional textChannelByIdOptional = channelService.getMessageChannelFromServerOptional(guildId, textChannelId); if(textChannelByIdOptional.isPresent()) { - TextChannel textChannel = textChannelByIdOptional.get(); - channelService.retrieveMessageInChannel(textChannel, messageId) + MessageChannel messageChannel = textChannelByIdOptional.get(); + channelService.retrieveMessageInChannel(messageChannel, messageId) .thenAccept(message -> cacheEntityService.buildCachedMessageFromMessage(message) .thenAccept(future::complete) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java index f817f06e7..d93567de6 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/MessageServiceBean.java @@ -76,7 +76,7 @@ public class MessageServiceBean implements MessageService { @Override public CompletableFuture deleteMessageInChannelInServer(Long serverId, Long channelId, Long messageId) { metricService.incrementCounter(MESSAGE_DELETE_METRIC); - return channelService.getTextChannelFromServer(serverId, channelId).deleteMessageById(messageId).submit(); + return channelService.getMessageChannelFromServer(serverId, channelId).deleteMessageById(messageId).submit(); } @Override diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PaginatorServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PaginatorServiceBean.java index 229ac66e3..4203449e2 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PaginatorServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/PaginatorServiceBean.java @@ -20,6 +20,7 @@ import lombok.Builder; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.TextChannel; import org.springframework.beans.factory.annotation.Autowired; @@ -73,7 +74,7 @@ public class PaginatorServiceBean implements PaginatorService { private static final ReentrantLock lock = new ReentrantLock(); @Override - public CompletableFuture createPaginatorFromTemplate(String templateKey, Object model, TextChannel textChannel, Long userId) { + public CompletableFuture createPaginatorFromTemplate(String templateKey, Object model, GuildMessageChannel textChannel, Long userId) { Long serverId = textChannel.getGuild().getIdLong(); String exitButtonId = componentService.generateComponentId(serverId); String startButtonId = componentService.generateComponentId(serverId); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java index a91d184da..4bbf69f4f 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/StartupServiceBean.java @@ -14,9 +14,7 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService; import dev.sheldan.abstracto.core.utils.SnowflakeUtils; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.GuildChannel; -import net.dv8tion.jda.api.entities.Role; +import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.hooks.ListenerAdapter; import org.apache.commons.collections4.SetUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -24,6 +22,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.security.auth.login.LoginException; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -138,26 +137,66 @@ public class StartupServiceBean implements Startup { Set existingRoleIds = SnowflakeUtils.getOwnItemsIds(existingRoles); Set guildRoleIds = SnowflakeUtils.getSnowflakeIds(guildRoles); Set newRoles = SetUtils.difference(guildRoleIds, existingRoleIds); - newRoles.forEach(aLong -> roleManagementService.createRole(aLong, existingAServer)); + newRoles.forEach(roleId -> roleManagementService.createRole(roleId, existingAServer)); Set deletedRoles = SetUtils.difference(existingRoleIds, guildRoleIds); - deletedRoles.forEach(aLong -> roleManagementService.markDeleted(aLong)); + deletedRoles.forEach(roleId -> roleManagementService.markDeleted(roleId)); } private void synchronizeChannelsOf(Guild guild, AServer existingServer){ List available = guild.getChannels(); - List knownChannels = existingServer.getChannels().stream().filter(aChannel -> !aChannel.getDeleted()).collect(Collectors.toList()); + List knownChannels = existingServer + .getChannels() + .stream() + .filter(aChannel -> !aChannel.getDeleted()) + .filter(aChannel -> !aChannel.getType().isThread()) + .collect(Collectors.toList()); Set knownChannelsIds = SnowflakeUtils.getOwnItemsIds(knownChannels); Set existingChannelsIds = SnowflakeUtils.getSnowflakeIds(available); Set newChannels = SetUtils.difference(existingChannelsIds, knownChannelsIds); - newChannels.forEach(aLong -> { - GuildChannel channel1 = available.stream().filter(channel -> channel.getIdLong() == aLong).findFirst().get(); - AChannelType type = AChannelType.getAChannelType(channel1.getType()); - channelManagementService.createChannel(channel1.getIdLong(), type, existingServer); + newChannels.forEach(channelId -> { + GuildChannel existingChannel = available + .stream() + .filter(channel -> channel.getIdLong() == channelId) + .findFirst() + .get(); + AChannelType type = AChannelType.getAChannelType(existingChannel.getType()); + channelManagementService.createChannel(existingChannel.getIdLong(), type, existingServer); }); - Set noLongAvailable = SetUtils.difference(knownChannelsIds, existingChannelsIds); - noLongAvailable.forEach(aLong -> - channelManagementService.markAsDeleted(aLong) + noLongAvailable.forEach(channelId -> + channelManagementService.markAsDeleted(channelId) + ); + List availableThreads = new ArrayList<>(); + List knownThreads = existingServer + .getChannels() + .stream() + .filter(aChannel -> !aChannel.getDeleted()) + .filter(aChannel -> aChannel.getType().isThread()) + .collect(Collectors.toList()); + available.stream().forEach(guildChannel -> { + if(guildChannel instanceof IThreadContainer) { + IThreadContainer threadContainer = (IThreadContainer) guildChannel; + availableThreads.addAll(threadContainer.getThreadChannels()); + } + }); + Set knownThreadIds = SnowflakeUtils.getOwnItemsIds(knownThreads); + Set existingThreadsIds = SnowflakeUtils.getSnowflakeIds(availableThreads); + Set newThreads = SetUtils.difference(existingThreadsIds, knownThreadIds); + + newThreads.forEach(threadId -> { + ThreadChannel existingThread = availableThreads + .stream() + .filter(channel -> channel.getIdLong() == threadId) + .findFirst() + .get(); + IThreadContainer parentChannel = existingThread.getParentChannel(); + AChannel parentChannelObj = channelManagementService.loadChannel(parentChannel); + AChannelType type = AChannelType.getAChannelType(existingThread.getType()); + channelManagementService.createThread(existingThread.getIdLong(), type, existingServer, parentChannelObj); + }); + Set noLongAvailableThreads = SetUtils.difference(knownThreadIds, existingThreadsIds); + noLongAvailableThreads.forEach(channelId -> + channelManagementService.markAsDeleted(channelId) ); } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java index eb70f4c52..7cb6be1ec 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementServiceBean.java @@ -10,6 +10,8 @@ import dev.sheldan.abstracto.core.models.listener.AChannelDeletedListenerModel; import dev.sheldan.abstracto.core.repository.ChannelRepository; import dev.sheldan.abstracto.core.service.LockService; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Channel; +import net.dv8tion.jda.api.entities.GuildChannel; import net.dv8tion.jda.api.entities.TextChannel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; @@ -41,8 +43,8 @@ public class ChannelManagementServiceBean implements ChannelManagementService { } @Override - public AChannel loadChannel(TextChannel textChannel) { - return loadChannel(textChannel.getIdLong()); + public AChannel loadChannel(Channel guildChannel) { + return loadChannel(guildChannel.getIdLong()); } @Override @@ -67,6 +69,29 @@ public class ChannelManagementServiceBean implements ChannelManagementService { } } + @Override + public AChannel createThread(Long id, AChannelType type, AServer server, AChannel parentChannel) { + lockService.lockTable(TableLocks.CHANNELS); + if(!channelExists(id)) { + log.info("Creating channel {} with type {}", id, type); + AChannel build = AChannel + .builder() + .id(id) + .type(type) + .relatedChannel(parentChannel) + .server(server) + .deleted(false) + .build(); + AChannel createdChannel = repository.save(build); + AChannelCreatedListenerModel model = getCreationModel(createdChannel); + eventPublisher.publishEvent(model); + return createdChannel; + } else { + Optional channelOptional = loadChannelOptional(id); + return channelOptional.orElse(null); + } + } + private AChannelCreatedListenerModel getCreationModel(AChannel channel) { return AChannelCreatedListenerModel .builder() diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/DiscordStartupService.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/startup/DiscordStartupListener.java similarity index 84% rename from abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/DiscordStartupService.java rename to abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/startup/DiscordStartupListener.java index 09ba824bb..d69e09204 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/DiscordStartupService.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/startup/DiscordStartupListener.java @@ -1,13 +1,14 @@ -package dev.sheldan.abstracto.core.service; +package dev.sheldan.abstracto.core.startup; import dev.sheldan.abstracto.core.listener.AsyncStartupListener; import dev.sheldan.abstracto.core.metric.service.CounterMetric; import dev.sheldan.abstracto.core.metric.service.MetricService; +import dev.sheldan.abstracto.core.service.BotService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component -public class DiscordStartupService implements AsyncStartupListener { +public class DiscordStartupListener implements AsyncStartupListener { public static final String DISCORD_GATEWAY_PING = "discord.gateway.ping"; private static final CounterMetric DISCORD_GATE_WAY_PING_METRIC = CounterMetric diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/startup/MessageContextCommandListenerLoader.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/startup/MessageContextCommandListenerLoader.java new file mode 100644 index 000000000..c6516e08b --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/startup/MessageContextCommandListenerLoader.java @@ -0,0 +1,86 @@ +package dev.sheldan.abstracto.core.startup; + +import dev.sheldan.abstracto.core.config.FeatureConfig; +import dev.sheldan.abstracto.core.listener.AsyncStartupListener; +import dev.sheldan.abstracto.core.listener.async.MessageContextCommandListener; +import dev.sheldan.abstracto.core.listener.sync.jda.MessageContextCommandListenerBean; +import dev.sheldan.abstracto.core.service.*; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.entities.ISnowflake; +import net.dv8tion.jda.api.interactions.commands.Command; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class MessageContextCommandListenerLoader implements AsyncStartupListener { + + @Autowired + private FeatureFlagService featureFlagService; + + @Autowired + private BotService botService; + + @Autowired + private FeatureConfigService featureConfigService; + + @Autowired + private FeatureModeService featureModeService; + + @Autowired + private MessageContextCommandListenerBean listenerBean; + + @Autowired + private ContextCommandService contextCommandService; + + @Override + public void execute() { + List contextListeners = listenerBean.getListenerList(); + if(contextListeners == null || contextListeners.isEmpty()) { + return; + } + JDA jda = botService.getInstance(); + List onlineGuilds = jda.getGuilds(); + onlineGuilds.forEach(guild -> { + log.info("Updating commands for guild {}.", guild.getIdLong()); + guild.retrieveCommands().queue(commands -> { + Map existingCommands = commands + .stream() + .filter(command -> command.getType().equals(Command.Type.MESSAGE)) + .collect(Collectors.toMap(Command::getName, ISnowflake::getIdLong)); + + log.info("Loaded {} commands for guild {}.", commands.size(), guild.getIdLong()); + contextListeners.forEach(listener -> { + FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(listener.getFeature()); + if (!featureFlagService.isFeatureEnabled(feature, guild.getIdLong())) { + return; + } + if(!featureModeService.necessaryFeatureModesMet(listener, guild.getIdLong())) { + return; + } + log.info("Updating message context command {} in guild {}.", listener.getConfig().getName(), guild.getId()); + if(existingCommands.containsKey(listener.getConfig().getName())) { + existingCommands.remove(listener.getConfig().getName()); + contextCommandService.upsertGuildMessageContextCommand(guild, listener.getConfig().getName()) + .thenAccept(command -> log.info("Updated message context command {} in guild {}.", listener.getConfig().getName(), guild.getId())); + } + }); + log.info("Deleting {} message context commands in guild {}.", existingCommands.values().size(), guild.getIdLong()); + existingCommands.forEach((commandName, commandId) -> + contextCommandService.deleteGuildContextCommand(guild, commandId) + .thenAccept(unused -> log.info("Deleted message context command {} with id {} in guild {}.", commandName, commandId, guild.getIdLong())) + .exceptionally(throwable -> { + log.warn("Failed to delete message context command {} with id {} in guild {}.", commandName, commandId, guild.getIdLong()); + return null; + })); + }, + throwable -> log.error("Failed to load commands for guild {}.", guild.getIdLong(), throwable)); + }); + + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/model/ButtonStyleConfig.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/model/ButtonStyleConfig.java index 004e6a37a..8df1ce060 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/model/ButtonStyleConfig.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/model/ButtonStyleConfig.java @@ -1,7 +1,7 @@ package dev.sheldan.abstracto.core.templating.model; import com.google.gson.annotations.SerializedName; -import net.dv8tion.jda.api.interactions.components.ButtonStyle; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; public enum ButtonStyleConfig { @SerializedName("primary") diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/service/TemplateServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/service/TemplateServiceBean.java index 0942e077d..0442d1ed4 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/service/TemplateServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/templating/service/TemplateServiceBean.java @@ -22,7 +22,7 @@ import net.dv8tion.jda.api.entities.Emoji; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.interactions.components.ActionRow; -import net.dv8tion.jda.api.interactions.components.Button; +import net.dv8tion.jda.api.interactions.components.buttons.Button; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/abstracto-application/core/core-impl/src/main/resources/abstracto.properties b/abstracto-application/core/core-impl/src/main/resources/abstracto.properties index b532031a7..925c642b6 100644 --- a/abstracto-application/core/core-impl/src/main/resources/abstracto.properties +++ b/abstracto-application/core/core-impl/src/main/resources/abstracto.properties @@ -1,6 +1,5 @@ abstracto.startup.synchronize=true -abstracto.eventWaiter.threads=3 server.port=8080 abstracto.allowedmention.everyone=false diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/collection.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/collection.xml new file mode 100644 index 000000000..35915fde6 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/collection.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/tables/channel.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/tables/channel.xml new file mode 100644 index 000000000..ed1ce647c --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/tables/channel.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + ALTER TABLE channel DROP CONSTRAINT check_channel_type; + ALTER TABLE channel ADD CONSTRAINT check_channel_type CHECK (type IN ('TEXT', 'DM', 'VOICE', 'NEWS', 'CATEGORY', 'NEWS_THREAD', 'PUBLIC_THREAD', 'PRIVATE_THREAD', 'STAGE', 'NEWS', 'UNKNOWN')); + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/tables/component_payload.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/tables/component_payload.xml new file mode 100644 index 000000000..c6a8d927e --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/tables/component_payload.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/tables/tables.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/tables/tables.xml new file mode 100644 index 000000000..12aee6d4c --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.4.0/tables/tables.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/core-changeLog.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/core-changeLog.xml index 038ec5e24..e411b67ff 100644 --- a/abstracto-application/core/core-impl/src/main/resources/migrations/core-changeLog.xml +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/core-changeLog.xml @@ -23,4 +23,5 @@ + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBeanTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupApplicationCommandServiceBeanTest.java similarity index 98% rename from abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBeanTest.java rename to abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupApplicationCommandServiceBeanTest.java index 963a48936..e67649ffa 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBeanTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupApplicationCommandServiceBeanTest.java @@ -20,7 +20,7 @@ import static dev.sheldan.abstracto.core.command.CommandConstants.COMMAND_CHANNE import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) -public class ChannelGroupCommandServiceBeanTest { +public class ChannelGroupApplicationCommandServiceBeanTest { @InjectMocks private ChannelGroupCommandServiceBean testUnit; diff --git a/abstracto-application/core/core-int/pom.xml b/abstracto-application/core/core-int/pom.xml index d37788869..5b3fff579 100644 --- a/abstracto-application/core/core-int/pom.xml +++ b/abstracto-application/core/core-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.core core - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 jar @@ -36,10 +36,6 @@ net.dv8tion JDA - - com.jagrosh - jda-utilities-menu - commons-io commons-io diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandContext.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandContext.java index 075eb635e..e767c4386 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandContext.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/execution/CommandContext.java @@ -7,10 +7,7 @@ import lombok.Builder; import lombok.Getter; import lombok.Setter; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; import java.util.List; @@ -18,7 +15,7 @@ import java.util.List; @Getter @Setter public class CommandContext { - private TextChannel channel; + private GuildMessageChannel channel; private Guild guild; private Member author; private Message message; diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionService.java index 88b2d5654..733306129 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/ExceptionService.java @@ -7,13 +7,12 @@ import dev.sheldan.abstracto.core.listener.async.jda.ButtonClickedListener; import dev.sheldan.abstracto.core.models.listener.ButtonClickedListenerModel; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.MessageChannel; -import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent; -import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; public interface ExceptionService { CommandResult reportExceptionToContext(Throwable exception, CommandContext context, Command command); void reportExceptionToInteraction(Throwable exception, ButtonClickedListenerModel interActionContext, ButtonClickedListener executedListener); - void reportExceptionToGuildMessageReceivedContext(Throwable exception, GuildMessageReceivedEvent event); - void reportExceptionToPrivateMessageReceivedContext(Throwable exception, PrivateMessageReceivedEvent event); + void reportExceptionToGuildMessageReceivedContext(Throwable exception, MessageReceivedEvent event); + void reportExceptionToPrivateMessageReceivedContext(Throwable exception, MessageReceivedEvent event); void reportExceptionToChannel(Throwable exception, MessageChannel channel, Member member); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interaction/MessageContextConfig.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interaction/MessageContextConfig.java new file mode 100644 index 000000000..395848027 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interaction/MessageContextConfig.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.core.interaction; + +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class MessageContextConfig { + private String name; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/AbstractConfigSetupStep.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/AbstractConfigSetupStep.java index d57c2b50c..0bf3366a9 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/AbstractConfigSetupStep.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/AbstractConfigSetupStep.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.core.interactive; +import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.templating.service.TemplateService; import lombok.Getter; @@ -7,6 +8,8 @@ import lombok.Setter; import net.dv8tion.jda.api.entities.Message; import org.springframework.beans.factory.annotation.Autowired; +import java.util.function.Consumer; + @Getter @Setter public abstract class AbstractConfigSetupStep implements SetupStep { @@ -26,8 +29,8 @@ public abstract class AbstractConfigSetupStep implements SetupStep { private InteractiveUtils interactiveUtils; - protected Runnable getTimeoutRunnable(Long serverId, Long channelId) { - return () -> interactiveUtils.sendTimeoutMessage(serverId, channelId); + protected Consumer getTimeoutConsumer(Long serverId, Long channelId) { + return (messageReceivedModel) -> interactiveUtils.sendTimeoutMessage(serverId, channelId); } protected boolean checkForExit(Message message) { diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/DelayedActionConfigContainer.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/DelayedActionConfigContainer.java new file mode 100644 index 000000000..9a99f4294 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/DelayedActionConfigContainer.java @@ -0,0 +1,14 @@ +package dev.sheldan.abstracto.core.interactive; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class DelayedActionConfigContainer { + private Class type; + private DelayedActionConfig object; + private String config; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveService.java index bdc8a27aa..3f92e0d69 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveService.java @@ -2,13 +2,12 @@ package dev.sheldan.abstracto.core.interactive; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.models.listener.MessageReceivedModel; import dev.sheldan.abstracto.core.templating.model.MessageToSend; -import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import java.util.function.Consumer; public interface InteractiveService { - void createMessageWithResponse(String templateKey, AUserInAServer responder, AChannel channel, Long messageId, Consumer action, Runnable finalAction); - void createMessageWithResponse(MessageToSend messageToSend, AUserInAServer responder, AChannel channel, Long messageId, Consumer action, Runnable finalAction); - void createMessageWithConfirmation(String text, AUserInAServer responder, AChannel channel, Long messageId, Consumer confirmation, Consumer denial, Runnable finalAction); + void createMessageWithResponse(String templateKey, AUserInAServer responder, AChannel channel, Consumer action, Consumer finalAction); + void createMessageWithResponse(MessageToSend messageToSend, AUserInAServer responder, AChannel channel, Consumer action, Consumer finalAction); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveUtils.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveUtils.java index 55a8d4cec..7cae4bcbf 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveUtils.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/InteractiveUtils.java @@ -2,13 +2,11 @@ package dev.sheldan.abstracto.core.interactive; import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.templating.service.TemplateService; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import java.util.Optional; - @Component public class InteractiveUtils { @@ -21,7 +19,7 @@ public class InteractiveUtils { @Transactional public void sendTimeoutMessage(Long serverId, Long channelId) { String s = templateService.renderSimpleTemplate("feature_setup_configuration_timeout", serverId); - Optional channelOptional = channelService.getTextChannelFromServerOptional(serverId, channelId); - channelOptional.ifPresent(channel -> channelService.sendTextToChannelNotAsync(s, channel)); + GuildMessageChannel channelOptional = channelService.getMessageChannelFromServer(serverId, channelId); + channelService.sendTextToChannelNotAsync(s, channelOptional); } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/SetupStepResult.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/SetupStepResult.java index 7877313bc..5ee9a2107 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/SetupStepResult.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/interactive/SetupStepResult.java @@ -10,10 +10,14 @@ import java.util.List; @Setter @Builder public class SetupStepResult { - private List delayedActionConfigList; + private List delayedActionConfigList; private SetupStepResultType result; public static SetupStepResult fromCancelled() { return SetupStepResult.builder().result(SetupStepResultType.CANCELLED).build(); } + + public static SetupStepResult fromSuccess() { + return SetupStepResult.builder().result(SetupStepResultType.SUCCESS).build(); + } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/async/MessageContextCommandListener.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/async/MessageContextCommandListener.java new file mode 100644 index 000000000..4a2c5ada7 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/async/MessageContextCommandListener.java @@ -0,0 +1,11 @@ +package dev.sheldan.abstracto.core.listener.async; + +import dev.sheldan.abstracto.core.interaction.MessageContextConfig; +import dev.sheldan.abstracto.core.listener.DefaultListenerResult; +import dev.sheldan.abstracto.core.listener.FeatureAwareListener; +import dev.sheldan.abstracto.core.models.listener.interaction.MessageContextInteractionModel; + +public interface MessageContextCommandListener extends FeatureAwareListener { + MessageContextConfig getConfig(); + Boolean handlesEvent(MessageContextInteractionModel model); +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureActivationListener.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureActivationListener.java new file mode 100644 index 000000000..ea285618c --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureActivationListener.java @@ -0,0 +1,8 @@ +package dev.sheldan.abstracto.core.listener.async.entity; + +import dev.sheldan.abstracto.core.listener.AbstractoListener; +import dev.sheldan.abstracto.core.listener.DefaultListenerResult; +import dev.sheldan.abstracto.core.models.listener.FeatureActivationListenerModel; + +public interface FeatureActivationListener extends AbstractoListener { +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureDeactivationListener.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureDeactivationListener.java new file mode 100644 index 000000000..88da2d4c9 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/FeatureDeactivationListener.java @@ -0,0 +1,8 @@ +package dev.sheldan.abstracto.core.listener.async.entity; + +import dev.sheldan.abstracto.core.listener.AbstractoListener; +import dev.sheldan.abstracto.core.listener.DefaultListenerResult; +import dev.sheldan.abstracto.core.models.listener.FeatureDeactivationListenerModel; + +public interface FeatureDeactivationListener extends AbstractoListener { +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/FullChannel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/FullChannel.java index 633eba56f..bc2672188 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/FullChannel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/FullChannel.java @@ -4,7 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AChannel; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.Channel; import java.io.Serializable; @@ -13,7 +13,7 @@ import java.io.Serializable; @Builder public class FullChannel implements Serializable { private AChannel channel; - private transient TextChannel serverChannel; + private transient Channel serverChannel; public String getChannelRepr() { if(serverChannel != null) { diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/GuildChannelMember.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/GuildChannelMember.java index ba4be6d5b..dd88de753 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/GuildChannelMember.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/GuildChannelMember.java @@ -3,15 +3,13 @@ package dev.sheldan.abstracto.core.models; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.*; @Getter @Setter @Builder public class GuildChannelMember { - public Guild guild; - private TextChannel textChannel; + private Guild guild; + private GuildChannel textChannel; private Member member; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/GuildMemberMessageChannel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/GuildMemberMessageChannel.java new file mode 100644 index 000000000..12ef351ea --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/GuildMemberMessageChannel.java @@ -0,0 +1,16 @@ +package dev.sheldan.abstracto.core.models; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.entities.*; + +@Getter +@Setter +@Builder +public class GuildMemberMessageChannel { + private Guild guild; + private GuildMessageChannel guildChannel; + private Member member; + private Message message; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/context/UserInitiatedServerContext.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/context/UserInitiatedServerContext.java index 3af2609d7..2544d3d6a 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/context/UserInitiatedServerContext.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/context/UserInitiatedServerContext.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.core.models.context; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -11,6 +12,7 @@ import net.dv8tion.jda.api.entities.MessageChannel; @Getter @NoArgsConstructor @Setter +@AllArgsConstructor @SuperBuilder public class UserInitiatedServerContext extends ServerContext { private MessageChannel messageChannel; diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannel.java index ffe105c1d..4f3173d96 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannel.java @@ -31,6 +31,12 @@ public class AChannel implements SnowFlake, Serializable { @JoinColumn(name = "server_id", nullable = false) private AServer server; + @ManyToOne(fetch = FetchType.LAZY) + @Getter + @Setter + @JoinColumn(name = "related_channel_id") + private AChannel relatedChannel; + @Getter @Enumerated(EnumType.STRING) private AChannelType type; diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelType.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelType.java index cfd146624..b083976a8 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelType.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelType.java @@ -3,15 +3,24 @@ package dev.sheldan.abstracto.core.models.database; import net.dv8tion.jda.api.entities.ChannelType; public enum AChannelType { - TEXT, DM, VOICE, NEWS, CATEGORY, UNKNOWN; + TEXT, DM, VOICE, NEWS, CATEGORY, UNKNOWN, NEWS_THREAD, PUBLIC_THREAD, PRIVATE_THREAD, STAGE; public static AChannelType getAChannelType(ChannelType type) { switch (type) { case TEXT: return AChannelType.TEXT; case PRIVATE: return AChannelType.DM; case VOICE: return AChannelType.VOICE; + case STAGE: return AChannelType.STAGE; + case NEWS: return AChannelType.NEWS; case CATEGORY: return AChannelType.CATEGORY; + case GUILD_NEWS_THREAD: return AChannelType.NEWS_THREAD; + case GUILD_PRIVATE_THREAD: return AChannelType.PRIVATE_THREAD; + case GUILD_PUBLIC_THREAD: return AChannelType.PUBLIC_THREAD; default: return AChannelType.UNKNOWN; } } + + public boolean isThread() { + return this == PUBLIC_THREAD || this == PRIVATE_THREAD || this == NEWS_THREAD; + } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/ComponentPayload.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/ComponentPayload.java index 6317e2ab9..d6b8fb77d 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/ComponentPayload.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/ComponentPayload.java @@ -21,7 +21,7 @@ public class ComponentPayload { @ManyToOne(fetch = FetchType.LAZY) @Getter @Setter - @JoinColumn(name = "server_id", nullable = false) + @JoinColumn(name = "server_id") private AServer server; @Lob diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/ButtonClickedListenerModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/ButtonClickedListenerModel.java index 0dcac4c47..69730df10 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/ButtonClickedListenerModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/ButtonClickedListenerModel.java @@ -5,20 +5,20 @@ import dev.sheldan.abstracto.core.models.template.button.ButtonPayload; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.events.interaction.ButtonClickEvent; +import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; @Getter @Setter @Builder public class ButtonClickedListenerModel implements FeatureAwareListenerModel { - private ButtonClickEvent event; + private ButtonInteractionEvent event; private String payload; private String origin; private ButtonPayload deserializedPayload; @Override public Long getServerId() { - return event.getGuild().getIdLong(); + return event.isFromGuild() ? event.getGuild().getIdLong() : null; } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/FeatureActivationListenerModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/FeatureActivationListenerModel.java new file mode 100644 index 000000000..967058b05 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/FeatureActivationListenerModel.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.core.models.listener; + +import dev.sheldan.abstracto.core.listener.ListenerModel; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class FeatureActivationListenerModel implements ListenerModel { + private String featureName; + private Long serverId; +} + diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/FeatureDeactivationListenerModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/FeatureDeactivationListenerModel.java new file mode 100644 index 000000000..cc090024e --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/FeatureDeactivationListenerModel.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.core.models.listener; + +import dev.sheldan.abstracto.core.listener.ListenerModel; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class FeatureDeactivationListenerModel implements ListenerModel { + private String featureName; + private Long serverId; +} + diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/ReactionClearedModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/ReactionClearedModel.java index 88e9ffeaf..7711a7d1a 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/ReactionClearedModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/ReactionClearedModel.java @@ -5,17 +5,18 @@ import dev.sheldan.abstracto.core.models.cache.CachedMessage; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.Channel; +import net.dv8tion.jda.api.entities.GuildChannel; @Getter @Setter @Builder public class ReactionClearedModel implements FeatureAwareListenerModel { private CachedMessage message; - private TextChannel channel; + private Channel channel; @Override public Long getServerId() { - return channel.getGuild().getIdLong(); + return channel instanceof GuildChannel ? ((GuildChannel) channel).getGuild().getIdLong() : null; } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/TextChannelCreatedModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/TextChannelCreatedModel.java index acc3045f1..863b3f9c6 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/TextChannelCreatedModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/TextChannelCreatedModel.java @@ -4,16 +4,17 @@ import dev.sheldan.abstracto.core.listener.FeatureAwareListenerModel; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.Channel; +import net.dv8tion.jda.api.entities.GuildChannel; @Getter @Setter @Builder public class TextChannelCreatedModel implements FeatureAwareListenerModel { - private TextChannel channel; + private Channel channel; @Override public Long getServerId() { - return channel.getGuild().getIdLong(); + return channel instanceof GuildChannel ? ((GuildChannel)channel).getGuild().getIdLong() : null; } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/TextChannelDeletedModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/TextChannelDeletedModel.java index e9a173761..b3dcc9f9f 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/TextChannelDeletedModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/TextChannelDeletedModel.java @@ -4,16 +4,17 @@ import dev.sheldan.abstracto.core.listener.FeatureAwareListenerModel; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.Channel; +import net.dv8tion.jda.api.entities.GuildChannel; @Getter @Setter @Builder public class TextChannelDeletedModel implements FeatureAwareListenerModel { - private TextChannel channel; + private Channel channel; @Override public Long getServerId() { - return channel.getGuild().getIdLong(); + return channel instanceof GuildChannel ? ((GuildChannel) channel).getGuild().getIdLong() : null; } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/VoiceChannelJoinedModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/VoiceChannelJoinedModel.java index ad67e1173..975e3e910 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/VoiceChannelJoinedModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/VoiceChannelJoinedModel.java @@ -4,8 +4,8 @@ import dev.sheldan.abstracto.core.listener.FeatureAwareListenerModel; import lombok.Builder; import lombok.Getter; import lombok.Setter; +import net.dv8tion.jda.api.entities.AudioChannel; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; @Getter @Setter @@ -13,7 +13,7 @@ import net.dv8tion.jda.api.entities.VoiceChannel; public class VoiceChannelJoinedModel implements FeatureAwareListenerModel { private Member member; - private VoiceChannel channel; + private AudioChannel channel; @Override public Long getServerId() { diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/VoiceChannelLeftModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/VoiceChannelLeftModel.java index e75b03639..d12d81785 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/VoiceChannelLeftModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/VoiceChannelLeftModel.java @@ -4,8 +4,8 @@ import dev.sheldan.abstracto.core.listener.FeatureAwareListenerModel; import lombok.Builder; import lombok.Getter; import lombok.Setter; +import net.dv8tion.jda.api.entities.AudioChannel; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.VoiceChannel; @Getter @Setter @@ -13,7 +13,7 @@ import net.dv8tion.jda.api.entities.VoiceChannel; public class VoiceChannelLeftModel implements FeatureAwareListenerModel { private Member member; - private VoiceChannel channel; + private AudioChannel channel; @Override public Long getServerId() { diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/interaction/MessageContextInteractionModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/interaction/MessageContextInteractionModel.java new file mode 100644 index 000000000..cad3ca6e6 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/listener/interaction/MessageContextInteractionModel.java @@ -0,0 +1,19 @@ +package dev.sheldan.abstracto.core.models.listener.interaction; + +import dev.sheldan.abstracto.core.listener.FeatureAwareListenerModel; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; + +@Getter +@Setter +@Builder +public class MessageContextInteractionModel implements FeatureAwareListenerModel { + private MessageContextInteractionEvent event; + + @Override + public Long getServerId() { + return event.isFromGuild() ? event.getGuild().getIdLong() : null; + } +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/ChannelGroupChannelModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/ChannelGroupChannelModel.java index 6b2da31b6..73c378cbd 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/ChannelGroupChannelModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/ChannelGroupChannelModel.java @@ -4,12 +4,12 @@ import dev.sheldan.abstracto.core.models.database.AChannel; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.MessageChannel; @Getter @Setter @Builder public class ChannelGroupChannelModel { private AChannel channel; - private TextChannel discordChannel; + private MessageChannel discordChannel; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/PostTargetActionModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/PostTargetActionModel.java index 2d00e6bf9..84bd8378a 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/PostTargetActionModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/PostTargetActionModel.java @@ -1,9 +1,9 @@ package dev.sheldan.abstracto.core.models.template.commands; +import dev.sheldan.abstracto.core.utils.ChannelUtils; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.TextChannel; @Getter @Setter @@ -11,5 +11,8 @@ import net.dv8tion.jda.api.entities.TextChannel; public class PostTargetActionModel { private String postTargetKey; private Long channelId; - private TextChannel channel; + + public String getChannelAsMention() { + return ChannelUtils.getAsMention(this.channelId); + } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/PostTargetModelEntry.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/PostTargetModelEntry.java index 0ecf096ae..3538b72a4 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/PostTargetModelEntry.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/PostTargetModelEntry.java @@ -4,13 +4,13 @@ import dev.sheldan.abstracto.core.models.database.PostTarget; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.MessageChannel; @Getter @Setter @Builder public class PostTargetModelEntry { private PostTarget postTarget; - private TextChannel channel; + private MessageChannel channel; private Boolean disabled; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupCompletedNotificationModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupCompletedNotificationModel.java index e673743a7..104e108cd 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupCompletedNotificationModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupCompletedNotificationModel.java @@ -1,6 +1,5 @@ package dev.sheldan.abstracto.core.models.template.commands; -import dev.sheldan.abstracto.core.config.FeatureConfig; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -9,5 +8,5 @@ import lombok.Setter; @Setter @Builder public class SetupCompletedNotificationModel { - private FeatureConfig featureConfig; + private String featureKey; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupPostTargetMessageModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupPostTargetMessageModel.java index b5cf417bf..6a30d8319 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupPostTargetMessageModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupPostTargetMessageModel.java @@ -3,12 +3,12 @@ package dev.sheldan.abstracto.core.models.template.commands; import lombok.Builder; import lombok.Getter; import lombok.Setter; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.MessageChannel; @Getter @Setter @Builder public class SetupPostTargetMessageModel { private String postTargetKey; - private TextChannel currentTextChannel; + private MessageChannel currentTextChannel; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupSummaryModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupSummaryModel.java index c0a29f2fc..f7764352d 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupSummaryModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/SetupSummaryModel.java @@ -1,6 +1,6 @@ package dev.sheldan.abstracto.core.models.template.commands; -import dev.sheldan.abstracto.core.interactive.DelayedActionConfig; +import dev.sheldan.abstracto.core.interactive.DelayedActionConfigContainer; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -11,5 +11,7 @@ import java.util.List; @Setter @Builder public class SetupSummaryModel { - private List actionConfigs; + private List actionConfigs; + private String confirmButtonId; + private String cancelButtonId; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/display/ChannelDisplay.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/display/ChannelDisplay.java index ae5df3ff1..fcbaa2109 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/display/ChannelDisplay.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/display/ChannelDisplay.java @@ -3,6 +3,7 @@ package dev.sheldan.abstracto.core.models.template.display; import lombok.Builder; import lombok.Getter; import lombok.Setter; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.TextChannel; @Getter @@ -22,4 +23,14 @@ public class ChannelDisplay { .channelMention(channel.getAsMention()) .build(); } -} + + public static ChannelDisplay fromChannel(GuildMessageChannel channel) { + if(channel == null) { + return null; + } + return ChannelDisplay + .builder() + .name(channel.getName()) + .channelMention(channel.getAsMention()) + .build(); + }} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ApplicationCommandService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ApplicationCommandService.java new file mode 100644 index 000000000..bb9fc3558 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ApplicationCommandService.java @@ -0,0 +1,9 @@ +package dev.sheldan.abstracto.core.service; + +import net.dv8tion.jda.api.entities.Guild; + +import java.util.concurrent.CompletableFuture; + +public interface ApplicationCommandService { + CompletableFuture deleteGuildCommand(Guild guild, Long commandId); +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java index 11edae32b..f95c35e3d 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ChannelService.java @@ -4,7 +4,6 @@ import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.templating.model.MessageToSend; import net.dv8tion.jda.api.entities.*; -import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.MessageAction; import java.util.List; @@ -16,7 +15,7 @@ public interface ChannelService { void sendTextToChannelNotAsync(String text, MessageChannel channel); CompletableFuture sendTextToAChannel(String text, AChannel channel); CompletableFuture sendMessageToAChannel(Message message, AChannel channel); - CompletableFuture sendMessageToChannel(Message message, MessageChannel channel); + CompletableFuture sendMessageToChannel(Message message, GuildMessageChannel channel); CompletableFuture sendTextToChannel(String text, MessageChannel channel); CompletableFuture sendEmbedToAChannel(MessageEmbed embed, AChannel channel); CompletableFuture sendEmbedToChannel(MessageEmbed embed, MessageChannel channel); @@ -34,7 +33,7 @@ public interface ChannelService { * @param textChannel The {@link MessageChannel} to send the messages to * @return A list of {@link CompletableFuture} representing each potential message sent */ - List> sendMessageToSendToChannel(MessageToSend messageToSend, MessageChannel textChannel); + List> sendMessageToSendToChannel(MessageToSend messageToSend, MessageChannel messageChannel); void editMessageInAChannel(MessageToSend messageToSend, AChannel channel, Long messageId); void editMessageInAChannel(MessageToSend messageToSend, MessageChannel channel, Long messageId); CompletableFuture editMessageInAChannelFuture(MessageToSend messageToSend, MessageChannel channel, Long messageId); @@ -47,23 +46,32 @@ public interface ChannelService { CompletableFuture removeFieldFromMessage(MessageChannel channel, Long messageId, Integer index, Integer embedIndex); CompletableFuture deleteTextChannel(AChannel channel); CompletableFuture deleteTextChannel(Long serverId, Long channelId); - List> sendEmbedTemplateInTextChannelList(String templateKey, Object model, TextChannel channel); + List> sendEmbedTemplateInTextChannelList(String templateKey, Object model, MessageChannel channel); List> sendEmbedTemplateInMessageChannelList(String templateKey, Object model, MessageChannel channel); - CompletableFuture sendTextTemplateInTextChannel(String templateKey, Object model, TextChannel channel); + CompletableFuture sendTextTemplateInTextChannel(String templateKey, Object model, MessageChannel channel); CompletableFuture sendTextTemplateInMessageChannel(String templateKey, Object model, MessageChannel channel); - RestAction deleteMessagesInChannel(TextChannel textChannel, List messages); + CompletableFuture deleteMessagesInChannel(MessageChannel messageChannel, List messages); CompletableFuture createTextChannel(String name, AServer server, Long categoryId); - Optional getChannelFromAChannel(AChannel channel); - AChannel getFakeChannelFromTextChannel(TextChannel textChannel); + Optional getChannelFromAChannel(AChannel channel); + Optional getGuildMessageChannelFromAChannelOptional(AChannel channel); + GuildMessageChannel getGuildMessageChannelFromAChannel(AChannel channel); + AChannel getFakeChannelFromTextChannel(MessageChannel messageChannel); CompletableFuture sendSimpleTemplateToChannel(Long serverId, Long channelId, String template); - CompletableFuture getHistoryOfChannel(TextChannel channel, Long startMessageId, Integer amount); - Optional getTextChannelFromServerOptional(Guild serverId, Long textChannelId); - TextChannel getTextChannelFromServer(Guild guild, Long textChannelId); - TextChannel getTextChannelFromServerNullable(Guild guild, Long textChannelId); + CompletableFuture getHistoryOfChannel(MessageChannel channel, Long startMessageId, Integer amount); + Optional getGuildChannelFromServerOptional(Guild serverId, Long textChannelId); + GuildMessageChannel getMessageChannelFromServer(Guild guild, Long textChannelId); + + GuildMessageChannel getMessageChannelFromServer(Long serverId, Long textChannelId); + Optional getMessageChannelFromServerOptional(Long serverId, Long textChannelId); + + GuildMessageChannel getMessageChannelFromServerNullable(Guild guild, Long textChannelId); + Optional getGuildChannelFromServerOptional(Long serverId, Long textChannelId); + + GuildChannel getGuildChannelFromServer(Long serverId, Long channelId); + Optional getTextChannelFromServerOptional(Long serverId, Long textChannelId); - TextChannel getTextChannelFromServer(Long serverId, Long textChannelId); CompletableFuture setSlowModeInChannel(TextChannel textChannel, Integer seconds); - List> sendFileToChannel(String fileContent, String fileNameTemplate, String messageTemplate, Object model, TextChannel channel); - List> sendFileToChannel(String fileContent, String fileName, TextChannel channel); + List> sendFileToChannel(String fileContent, String fileNameTemplate, String messageTemplate, Object model, MessageChannel channel); + List> sendFileToChannel(String fileContent, String fileName, MessageChannel channel); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ComponentService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ComponentService.java index 77c1755e7..5444f54bf 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ComponentService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ComponentService.java @@ -1,11 +1,12 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.models.template.button.ButtonConfigModel; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import net.dv8tion.jda.api.entities.Message; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.interactions.components.ActionComponent; import net.dv8tion.jda.api.interactions.components.ActionRow; -import net.dv8tion.jda.api.interactions.components.ButtonStyle; import net.dv8tion.jda.api.interactions.components.Component; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -15,12 +16,12 @@ public interface ComponentService { Integer MAX_BUTTONS_PER_ROW = Component.Type.BUTTON.getMaxPerRow(); String generateComponentId(Long serverId); String generateComponentId(); - CompletableFuture addButtonToMessage(Long messageId, TextChannel textChannel, String buttonId, String description, String emoteMarkdown, ButtonStyle style); + CompletableFuture addButtonToMessage(Long messageId, GuildMessageChannel textChannel, String buttonId, String description, String emoteMarkdown, ButtonStyle style); CompletableFuture clearButtons(Message message); CompletableFuture disableAllButtons(Message message); CompletableFuture enableAllButtons(Message message); CompletableFuture removeComponentWithId(Message message, String componentId); CompletableFuture removeComponentWithId(Message message, String componentId, Boolean rearrange); - List splitIntoActionRowsMax(List components); + List splitIntoActionRowsMax(List components); ButtonConfigModel createButtonConfigModel(); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ContextCommandService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ContextCommandService.java new file mode 100644 index 000000000..4048d2f9f --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ContextCommandService.java @@ -0,0 +1,12 @@ +package dev.sheldan.abstracto.core.service; + +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.interactions.commands.Command; + +import java.util.concurrent.CompletableFuture; + +public interface ContextCommandService { + CompletableFuture upsertGuildMessageContextCommand(Guild guild, String name); + CompletableFuture deleteGuildContextCommand(Guild guild, Long commandId); + CompletableFuture deleteGuildContextCommandByName(Guild guild, String commandName); +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/FeatureConfigService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/FeatureConfigService.java index 54fbbb510..07db723e8 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/FeatureConfigService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/FeatureConfigService.java @@ -4,6 +4,9 @@ import dev.sheldan.abstracto.core.config.FeatureConfig; import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureMode; import dev.sheldan.abstracto.core.config.PostTargetEnum; +import dev.sheldan.abstracto.core.listener.FeatureAwareListener; +import dev.sheldan.abstracto.core.listener.FeatureAwareListenerModel; +import dev.sheldan.abstracto.core.listener.ListenerExecutionResult; import dev.sheldan.abstracto.core.models.FeatureValidationResult; import dev.sheldan.abstracto.core.models.database.AFeature; import dev.sheldan.abstracto.core.models.database.AServer; @@ -25,4 +28,5 @@ public interface FeatureConfigService { FeatureMode getFeatureModeByKey(FeatureConfig featureConfig, String key); FeatureConfig getFeatureConfigForFeature(AFeature feature); boolean isModeValid(String featureName, String modeName); + boolean isFeatureAwareEnabled(FeatureAwareListener listener, Long serverId); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/FeatureSetupService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/FeatureSetupService.java index 998d91698..3137ad973 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/FeatureSetupService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/FeatureSetupService.java @@ -1,7 +1,7 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.config.FeatureConfig; -import dev.sheldan.abstracto.core.interactive.DelayedActionConfig; +import dev.sheldan.abstracto.core.interactive.DelayedActionConfigContainer; import dev.sheldan.abstracto.core.interactive.SetupExecution; import dev.sheldan.abstracto.core.models.AServerChannelUserId; @@ -10,5 +10,5 @@ import java.util.concurrent.CompletableFuture; public interface FeatureSetupService { CompletableFuture performFeatureSetup(FeatureConfig featureConfig, AServerChannelUserId user, Long initialMessageId); - CompletableFuture executeFeatureSetup(FeatureConfig featureConfig, List steps, AServerChannelUserId user, List delayedActionConfigs); + CompletableFuture executeFeatureSetup(FeatureConfig featureConfig, List steps, AServerChannelUserId user, List delayedActionConfigs); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/PaginatorService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/PaginatorService.java index bba843dc9..2ddaa232b 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/PaginatorService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/PaginatorService.java @@ -1,10 +1,10 @@ package dev.sheldan.abstracto.core.service; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import java.util.concurrent.CompletableFuture; public interface PaginatorService { - CompletableFuture createPaginatorFromTemplate(String templateKey, Object model, TextChannel textChannel, Long userId); + CompletableFuture createPaginatorFromTemplate(String templateKey, Object model, GuildMessageChannel textChannel, Long userId); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java index 69915c0ed..df55de409 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelManagementService.java @@ -3,15 +3,16 @@ package dev.sheldan.abstracto.core.service.management; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannelType; import dev.sheldan.abstracto.core.models.database.AServer; -import net.dv8tion.jda.api.entities.TextChannel; +import net.dv8tion.jda.api.entities.Channel; import java.util.Optional; public interface ChannelManagementService { Optional loadChannelOptional(Long id); AChannel loadChannel(Long id); - AChannel loadChannel(TextChannel textChannel); + AChannel loadChannel(Channel textChannel); AChannel createChannel(Long id, AChannelType type, AServer server); + AChannel createThread(Long id, AChannelType type, AServer server, AChannel parentChannel); AChannel markAsDeleted(Long id); boolean channelExists(Long id); void removeChannel(Long id); diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/utils/ChannelUtils.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/utils/ChannelUtils.java index 796697ee3..2945ce90e 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/utils/ChannelUtils.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/utils/ChannelUtils.java @@ -9,4 +9,8 @@ public class ChannelUtils { public static String buildChannelUrl(Long serverId, Long channelId) { return String.format("https://discord.com/channels/%s/%s/", serverId, channelId); } + + public static String getAsMention(Long channelId) { + return "<#" + channelId + '>'; + } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java index 4c3d62983..3475525ee 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/utils/ContextUtils.java @@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.service.MemberService; import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.GuildMessageChannel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -36,7 +37,7 @@ public class ContextUtils { return builder .member(guildChannelMember.getMember()) .guild(guildChannelMember.getGuild()) - .messageChannel(guildChannelMember.getTextChannel()) + .messageChannel((GuildMessageChannel) guildChannelMember.getTextChannel()) .build(); } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { log.error("Failed to execute builder method", e); diff --git a/abstracto-application/core/metrics-impl/pom.xml b/abstracto-application/core/metrics-impl/pom.xml index 854d96450..9f3c0fda9 100644 --- a/abstracto-application/core/metrics-impl/pom.xml +++ b/abstracto-application/core/metrics-impl/pom.xml @@ -3,7 +3,7 @@ core dev.sheldan.abstracto.core - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/core/metrics-int/pom.xml b/abstracto-application/core/metrics-int/pom.xml index c697165fe..8c2b5e734 100644 --- a/abstracto-application/core/metrics-int/pom.xml +++ b/abstracto-application/core/metrics-int/pom.xml @@ -3,7 +3,7 @@ core dev.sheldan.abstracto.core - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/core/pom.xml b/abstracto-application/core/pom.xml index 7be6e1c34..1e349c937 100644 --- a/abstracto-application/core/pom.xml +++ b/abstracto-application/core/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto abstracto-application - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/coverage/pom.xml b/abstracto-application/coverage/pom.xml index 40f4f1d4c..44aafe765 100644 --- a/abstracto-application/coverage/pom.xml +++ b/abstracto-application/coverage/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto abstracto-application - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 coverage diff --git a/abstracto-application/documentation/pom.xml b/abstracto-application/documentation/pom.xml index 1455b5dcc..c7f557a8e 100644 --- a/abstracto-application/documentation/pom.xml +++ b/abstracto-application/documentation/pom.xml @@ -3,7 +3,7 @@ abstracto-application dev.sheldan.abstracto - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/installer/pom.xml b/abstracto-application/installer/pom.xml index 29f9f944e..7536b0edd 100644 --- a/abstracto-application/installer/pom.xml +++ b/abstracto-application/installer/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto abstracto-application - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/pom.xml b/abstracto-application/pom.xml index 83cbfe1e9..a5d00d2f2 100644 --- a/abstracto-application/pom.xml +++ b/abstracto-application/pom.xml @@ -11,7 +11,7 @@ dev.sheldan.abstracto abstracto-application - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT pom @@ -57,7 +57,7 @@ yyyy/MM/dd HH:mm - 4.3.0_315 + 5.0.0-alpha.9 3.0.4 2.0.0-RC.1 1.5.3 @@ -182,12 +182,6 @@ - - com.jagrosh - jda-utilities-menu - ${jda.utilities.version} - compile - org.apache.commons commons-lang3 diff --git a/abstracto-application/scheduling/pom.xml b/abstracto-application/scheduling/pom.xml index d49233f13..1327e2fdf 100644 --- a/abstracto-application/scheduling/pom.xml +++ b/abstracto-application/scheduling/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto abstracto-application - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 diff --git a/abstracto-application/scheduling/scheduling-impl/pom.xml b/abstracto-application/scheduling/scheduling-impl/pom.xml index 98a58ebf1..95271306a 100644 --- a/abstracto-application/scheduling/scheduling-impl/pom.xml +++ b/abstracto-application/scheduling/scheduling-impl/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.scheduling scheduling - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 jar diff --git a/abstracto-application/scheduling/scheduling-int/pom.xml b/abstracto-application/scheduling/scheduling-int/pom.xml index 9c8898924..f1203d3ea 100644 --- a/abstracto-application/scheduling/scheduling-int/pom.xml +++ b/abstracto-application/scheduling/scheduling-int/pom.xml @@ -3,7 +3,7 @@ dev.sheldan.abstracto.scheduling scheduling - 1.3.14-SNAPSHOT + 1.4.0-SNAPSHOT 4.0.0 jar diff --git a/bundled-licenses/direct/JDA-utilities/LICENSE.md b/bundled-licenses/direct/JDA-utilities/LICENSE.md deleted file mode 100644 index e7d0b95e0..000000000 --- a/bundled-licenses/direct/JDA-utilities/LICENSE.md +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2016-2018 John Grosh (jagrosh) & Kaidan Gustave (TheMonitorLizard) - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/bundled-licenses/direct/JDA-utilities/info.txt b/bundled-licenses/direct/JDA-utilities/info.txt deleted file mode 100644 index cf4c350aa..000000000 --- a/bundled-licenses/direct/JDA-utilities/info.txt +++ /dev/null @@ -1 +0,0 @@ -https://github.com/JDA-Applications/JDA-Utilities \ No newline at end of file