mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-17 12:34:46 +00:00
[AB-358] upgrading to JDA 5
removal of jda-utils adding message context commands [AB-360] fixing confirmation buttons being triggered by somebody not the author
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>dev.sheldan.abstracto.core</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>1.3.14-SNAPSHOT</version>
|
||||
<version>1.4.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -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<CommandParseResult> 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<ConditionResult> 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<Void> 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<Parameters> getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message){
|
||||
public CompletableFuture<Parameters> getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message) {
|
||||
List<ParseResult> parsedParameters = new ArrayList<>();
|
||||
List<Parameter> 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<Parameters> multipleFuturesFuture = new CompletableFuture<>();
|
||||
CompletableFuture<Void> combinedFuture = FutureUtils.toSingleFuture(futures);
|
||||
combinedFuture.thenAccept(aVoid -> {
|
||||
List<Object> 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<ParseResult> 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<Object> extractParametersFromParsed(List<ParseResult> results) {
|
||||
List<Object> 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<Object> 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<PostTargetModelEntry> postTargetEntries = posttargetDisplayModel.getPostTargets();
|
||||
postTargets.forEach(target -> {
|
||||
Optional<TextChannel> channelFromAChannel = channelService.getChannelFromAChannel(target.getChannelReference());
|
||||
Optional<GuildMessageChannel> channelFromAChannel = channelService.getGuildMessageChannelFromAChannelOptional(target.getChannelReference());
|
||||
PostTargetModelEntry targetEntry = PostTargetModelEntry
|
||||
.builder()
|
||||
.channel(channelFromAChannel.orElse(null))
|
||||
|
||||
@@ -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<CustomJsonSerializer> customJsonSerializers;
|
||||
|
||||
@Autowired
|
||||
private List<CustomJsonDeSerializer> 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
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package dev.sheldan.abstracto.core.config;
|
||||
|
||||
public interface CustomJsonDeSerializer {
|
||||
Class getType();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package dev.sheldan.abstracto.core.config;
|
||||
|
||||
public interface CustomJsonSerializer {
|
||||
Class getType();
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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<DelayedActionConfigContainer> actions) {
|
||||
List<DelayedActionConfig> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<Long, Map<Long, Map<Long, MessageInteractionCallback>>> 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<Long, Map<Long, MessageInteractionCallback>> channelMap = callbacks.get(model.getServerId());
|
||||
if(channelMap.containsKey(model.getMessage().getChannel().getIdLong())) {
|
||||
Map<Long, MessageInteractionCallback> 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<Long, Map<Long, MessageInteractionCallback>> channelMap = new HashMap<>();
|
||||
if(callbacks.containsKey(interactiveCallBack.getServerId())) {
|
||||
channelMap = callbacks.get(interactiveCallBack.getServerId());
|
||||
} else {
|
||||
callbacks.put(interactiveCallBack.getServerId(), channelMap);
|
||||
}
|
||||
Map<Long, MessageInteractionCallback> 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<MessageReceivedEvent> action, Runnable finalAction) {
|
||||
public void createMessageWithResponse(String messageText, AUserInAServer responder, AChannel channel, Consumer<MessageReceivedModel> action, Consumer<MessageReceivedModel> 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<MessageReceivedEvent> action, Runnable finalAction) {
|
||||
public void createMessageWithResponse(MessageToSend messageToSend, AUserInAServer responder, AChannel channel,
|
||||
Consumer<MessageReceivedModel> action, Consumer<MessageReceivedModel> 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<Void> confirmation, Consumer<Void> denial, Runnable finalAction) {
|
||||
Long serverId = responder.getServerReference().getId();
|
||||
ButtonMenu.Builder builder = new ButtonMenu.Builder();
|
||||
HashMap<String, Consumer<Void>> 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<MessageReceivedModel> action, Consumer<MessageReceivedModel> timeoutAction) {
|
||||
MessageInteractionCallback callBack = MessageInteractionCallback
|
||||
.builder()
|
||||
.serverId(channel.getServer().getId())
|
||||
.channelId(channel.getId())
|
||||
.userId(responder.getUserReference().getId())
|
||||
.action(action)
|
||||
.timeoutAction(timeoutAction)
|
||||
.build();
|
||||
Optional<TextChannel> textChannelInGuild = channelService.getTextChannelFromServerOptional(serverId, channel.getId());
|
||||
textChannelInGuild.ifPresent(menu::display);
|
||||
interactiveMessageReceivedListener.addCallback(callBack);
|
||||
}
|
||||
|
||||
private void addEmoteToBuilder(String key, Consumer<Void> consumer, Long serverId, ButtonMenu.Builder builder, HashMap<String, Consumer<Void>> actions) {
|
||||
AEmote emoteOrFakeEmote = emoteService.getEmoteOrDefaultEmote(key, serverId);
|
||||
if(Boolean.TRUE.equals(emoteOrFakeEmote.getCustom())){
|
||||
Optional<Emote> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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<SetupStepResult> 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<SetupStepResult> 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<Void> 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<Void> 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());
|
||||
}
|
||||
}
|
||||
@@ -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<DelayedActionConfig> delayedActionList;
|
||||
private List<DelayedActionConfigContainer> delayedActionList;
|
||||
private FeatureConfig featureConfig;
|
||||
}
|
||||
|
||||
@@ -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<DelayedActionConfigContainer>, 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;
|
||||
}
|
||||
}
|
||||
@@ -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<DelayedActionConfigContainer> {
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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<MessageReceivedModel> action;
|
||||
private Consumer<MessageReceivedModel> timeoutAction;
|
||||
private Instant timeoutPoint;
|
||||
|
||||
public Predicate<MessageReceivedModel> condition;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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<DelayedActionConfigContainer> actions;
|
||||
|
||||
public enum SetupConfirmationAction {
|
||||
CONFIRM, ABORT
|
||||
}
|
||||
}
|
||||
@@ -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<SetupStepResult> 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<SetupStepResult> future = new CompletableFuture<>();
|
||||
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(user.getGuildId(), user.getUserId());
|
||||
Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId());
|
||||
Consumer<MessageReceivedModel> 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<MessageReceivedEvent> configAction = (MessageReceivedEvent event) -> {
|
||||
Consumer<MessageReceivedModel> 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<DelayedActionConfig> delayedSteps = Arrays.asList(build);
|
||||
DelayedActionConfigContainer container = DelayedActionConfigContainer
|
||||
.builder()
|
||||
.type(build.getClass())
|
||||
.object(build)
|
||||
.build();
|
||||
List<DelayedActionConfigContainer> 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;
|
||||
}
|
||||
|
||||
@@ -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<SetupStepResult> 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<CompletableFuture<Message>> 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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<MessageReceivedEvent> configAction = (MessageReceivedEvent event) -> {
|
||||
Consumer<MessageReceivedModel> finalAction = super.getTimeoutConsumer(user.getGuildId(), user.getChannelId());
|
||||
Consumer<MessageReceivedModel> 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<DelayedActionConfig> delayedSteps = Arrays.asList(build);
|
||||
DelayedActionConfigContainer container = DelayedActionConfigContainer
|
||||
.builder()
|
||||
.type(build.getClass())
|
||||
.object(build)
|
||||
.build();
|
||||
List<DelayedActionConfigContainer> 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());
|
||||
}
|
||||
|
||||
@@ -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<MessageContextCommandListener> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<MessageContextCommandListener> 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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<FeatureActivationListener> 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<FeatureDeactivationListener> 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<CachedMessage> cachedMessageConsumer = cachedMessage -> {
|
||||
MessageDeletedModel model = getModel(cachedMessage);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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<CachedMessage> 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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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<MessageContextCommandListener> 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<MessageContextCommandListener> validListener = filterFeatureAwareListener(listenerList, model);
|
||||
Optional<MessageContextCommandListener> 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<MessageContextCommandListener> findListener(List<MessageContextCommandListener> featureAwareListeners, MessageContextInteractionModel model) {
|
||||
return featureAwareListeners.stream().filter(contextListener -> contextListener.handlesEvent(model)).findFirst();
|
||||
}
|
||||
|
||||
private List<MessageContextCommandListener> filterFeatureAwareListener(List<MessageContextCommandListener> 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<MessageContextCommandListener> getListenerList() {
|
||||
return listenerList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<CachedMessage> cachedMessageConsumer = cachedMessage -> {
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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<CachedMessage> asyncMessageFromCache = messageCache.getMessageFromCache(event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong());
|
||||
asyncMessageFromCache.thenAccept(cachedMessage -> {
|
||||
cachedMessage.getReactions().clear();
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<ButtonClickedListener> filterFeatureAwareListener(List<ButtonClickedListener> 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()));
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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<Void> deleteGuildCommand(Guild guild, Long commandId) {
|
||||
return guild.deleteCommandById(commandId).submit();
|
||||
}
|
||||
}
|
||||
@@ -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<ChannelGroupChannelModel> convertedChannels = new ArrayList<>();
|
||||
group.getChannels().forEach(channel -> {
|
||||
Optional<TextChannel> textChannelInGuild = channelService.getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId());
|
||||
Optional<GuildMessageChannel> textChannelInGuild = channelService.getGuildMessageChannelFromAChannelOptional(channel);
|
||||
ChannelGroupChannelModel convertedChannel = ChannelGroupChannelModel
|
||||
.builder()
|
||||
.channel(channel)
|
||||
|
||||
@@ -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<Message> 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<Message> sendMessageToAChannel(Message message, AChannel channel) {
|
||||
Optional<TextChannel> 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<Message> sendMessageToChannel(Message message, MessageChannel channel) {
|
||||
public CompletableFuture<Message> 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<CompletableFuture<Message>> sendMessageEmbedToSendToAChannel(MessageToSend messageToSend, AChannel channel) {
|
||||
Optional<TextChannel> 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<Message> 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<ActionRow> actionRows = messageToSend.getActionRows();
|
||||
if(!actionRows.isEmpty() && textChannel instanceof GuildChannel) {
|
||||
GuildChannel channel = (GuildChannel) textChannel;
|
||||
if(!actionRows.isEmpty()) {
|
||||
List<List<ActionRow>> 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<TextChannel> textChannelFromServer = getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId());
|
||||
if(textChannelFromServer.isPresent()) {
|
||||
TextChannel textChannel = textChannelFromServer.get();
|
||||
editMessageInAChannel(messageToSend, textChannel, messageId);
|
||||
Optional<GuildChannel> 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<CompletableFuture<Message>> sendEmbedTemplateInTextChannelList(String templateKey, Object model, TextChannel channel) {
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(templateKey, model, channel.getGuild().getIdLong());
|
||||
public List<CompletableFuture<Message>> 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<Message> sendTextTemplateInTextChannel(String templateKey, Object model, TextChannel channel) {
|
||||
String text = templateService.renderTemplate(templateKey, model, channel.getGuild().getIdLong());
|
||||
public CompletableFuture<Message> 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<Void> deleteMessagesInChannel(TextChannel textChannel, List<Message> messages) {
|
||||
public CompletableFuture<Void> deleteMessagesInChannel(MessageChannel messageChannel, List<Message> messages) {
|
||||
metricService.incrementCounter(CHANNEL_MESSAGE_BULK_DELETE_METRIC);
|
||||
return textChannel.deleteMessages(messages);
|
||||
List<CompletableFuture<Void>> 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<TextChannel> getChannelFromAChannel(AChannel channel) {
|
||||
return getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId());
|
||||
public Optional<GuildChannel> 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<GuildMessageChannel> 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<Message> 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<MessageHistory> getHistoryOfChannel(TextChannel channel, Long startMessageId, Integer amount) {
|
||||
public CompletableFuture<MessageHistory> getHistoryOfChannel(MessageChannel channel, Long startMessageId, Integer amount) {
|
||||
return channel.getHistoryBefore(startMessageId, amount).submit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TextChannel> getTextChannelFromServerOptional(Guild guild, Long textChannelId) {
|
||||
return Optional.ofNullable(guild.getTextChannelById(textChannelId));
|
||||
public Optional<GuildChannel> 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<Guild> guildOptional = guildService.getGuildByIdOptional(serverId);
|
||||
if(guildOptional.isPresent()) {
|
||||
Guild guild = guildOptional.get();
|
||||
return getMessageChannelFromServer(guild, textChannelId);
|
||||
}
|
||||
throw new GuildNotFoundException(serverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TextChannel> getTextChannelFromServerOptional(Long serverId, Long textChannelId) {
|
||||
public Optional<GuildMessageChannel> getMessageChannelFromServerOptional(Long serverId, Long textChannelId) {
|
||||
Optional<GuildChannel> 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<GuildChannel> getGuildChannelFromServerOptional(Long serverId, Long channelId) {
|
||||
Optional<Guild> 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<Guild> guildOptional = guildService.getGuildByIdOptional(serverId);
|
||||
if(guildOptional.isPresent()) {
|
||||
Guild guild = guildOptional.get();
|
||||
return guild.getGuildChannelById(channelId);
|
||||
}
|
||||
throw new GuildNotFoundException(serverId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TextChannel> getTextChannelFromServerOptional(Long serverId, Long textChannelId) {
|
||||
Optional<Guild> 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<Void> setSlowModeInChannel(TextChannel textChannel, Integer seconds) {
|
||||
@@ -521,17 +587,23 @@ public class ChannelServiceBean implements ChannelService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompletableFuture<Message>> sendFileToChannel(String fileContent, String fileNameTemplate, String messageTemplate, Object model, TextChannel channel) {
|
||||
public List<CompletableFuture<Message>> 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<CompletableFuture<Message>> sendFileToChannel(String fileContent, String fileName, TextChannel channel) {
|
||||
public List<CompletableFuture<Message>> 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()
|
||||
|
||||
@@ -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<Message> addButtonToMessage(Long messageId, TextChannel textChannel, String buttonId, String description, String emoteMarkdown, ButtonStyle style) {
|
||||
public CompletableFuture<Message> 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<Void> removeComponentWithId(Message message, String componentId, Boolean rearrange) {
|
||||
List<ActionRow> actionRows = new ArrayList<>();
|
||||
if(Boolean.TRUE.equals(rearrange)) {
|
||||
List<net.dv8tion.jda.api.interactions.components.Component> components = new ArrayList<>();
|
||||
List<net.dv8tion.jda.api.interactions.components.ActionComponent> 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<ActionRow> splitIntoActionRowsMax(List<net.dv8tion.jda.api.interactions.components.Component> allComponents) {
|
||||
List<List<net.dv8tion.jda.api.interactions.components.Component>> actionRows = ListUtils.partition(allComponents, MAX_BUTTONS_PER_ROW);
|
||||
public List<ActionRow> splitIntoActionRowsMax(List<net.dv8tion.jda.api.interactions.components.ActionComponent> allComponents) {
|
||||
List<List<net.dv8tion.jda.api.interactions.components.ActionComponent>> 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<Void> setAllButtonStatesTo(Message message, Boolean disabled) {
|
||||
List<ActionRow> actionRows = new ArrayList<>();
|
||||
|
||||
message.getActionRows().forEach(row -> {
|
||||
List<net.dv8tion.jda.api.interactions.components.Component> 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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Command> upsertGuildMessageContextCommand(Guild guild, String name) {
|
||||
return guild.upsertCommand(Commands.context(Command.Type.MESSAGE, name)).submit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> deleteGuildContextCommand(Guild guild, Long commandId) {
|
||||
return applicationCommandService.deleteGuildCommand(guild, commandId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> deleteGuildContextCommandByName(Guild guild, String commandName) {
|
||||
return guild.retrieveCommands().submit().thenCompose(commands -> {
|
||||
Optional<Command> 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));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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<String> getAllFeatures() {
|
||||
return availableFeatures
|
||||
@@ -148,4 +157,16 @@ public class FeatureConfigServiceBean implements FeatureConfigService {
|
||||
.anyMatch(featureMode -> featureMode.getKey().equalsIgnoreCase(modeName))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends FeatureAwareListenerModel, R extends ListenerExecutionResult> boolean isFeatureAwareEnabled(FeatureAwareListener<T, R> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Void> 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<TextChannel> textChannelInGuild = channelService.getTextChannelFromServerOptional(user.getGuildId(), user.getChannelId());
|
||||
if (textChannelInGuild.isPresent()) {
|
||||
Set<String> requiredSystemConfigKeys = new HashSet<>();
|
||||
Set<PostTargetEnum> requiredPostTargets = new HashSet<>();
|
||||
Set<SetupStep> customSetupSteps = new HashSet<>();
|
||||
GuildMessageChannel messageChannelInGuild = channelService.getMessageChannelFromServer(user.getGuildId(), user.getChannelId());
|
||||
Set<String> requiredSystemConfigKeys = new HashSet<>();
|
||||
Set<PostTargetEnum> requiredPostTargets = new HashSet<>();
|
||||
Set<SetupStep> customSetupSteps = new HashSet<>();
|
||||
|
||||
collectRequiredFeatureSteps(featureConfig, requiredSystemConfigKeys, requiredPostTargets, customSetupSteps, new HashSet<>());
|
||||
collectRequiredFeatureSteps(featureConfig, requiredSystemConfigKeys, requiredPostTargets, customSetupSteps, new HashSet<>());
|
||||
|
||||
List<SetupExecution> 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<SetupExecution> 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<DelayedActionConfig> 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<DelayedActionConfigContainer> 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<Void> executeFeatureSetup(FeatureConfig featureConfig, List<SetupExecution> steps, AServerChannelUserId user, List<DelayedActionConfig> delayedActionConfigs) {
|
||||
public CompletableFuture<Void> executeFeatureSetup(FeatureConfig featureConfig, List<SetupExecution> steps, AServerChannelUserId user, List<DelayedActionConfigContainer> 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<Void> executeStep(AServerChannelUserId aUserInAServer, SetupExecution execution, List<DelayedActionConfig> delayedActionConfigs, FeatureConfig featureConfig) {
|
||||
private CompletableFuture<Void> executeStep(AServerChannelUserId aUserInAServer, SetupExecution execution, List<DelayedActionConfigContainer> 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<TextChannel> 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<DelayedActionConfig> delayedActionConfigs, AServerChannelUserId user, Long initialMessage, FeatureConfig featureConfig) {
|
||||
public void executePostSetupSteps(List<DelayedActionConfigContainer> 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> 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<String> requiredSystemConfigKeys,
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -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<TextChannel> 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<Member> 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()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<CachedMessage> future = new CompletableFuture<>();
|
||||
Optional<Guild> guildOptional = guildService.getGuildByIdOptional(guildId);
|
||||
if(guildOptional.isPresent()) {
|
||||
Optional<TextChannel> textChannelByIdOptional = channelService.getTextChannelFromServerOptional(guildOptional.get(), textChannelId);
|
||||
Optional<GuildMessageChannel> 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)
|
||||
|
||||
@@ -76,7 +76,7 @@ public class MessageServiceBean implements MessageService {
|
||||
@Override
|
||||
public CompletableFuture<Void> 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
|
||||
|
||||
@@ -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<Void> createPaginatorFromTemplate(String templateKey, Object model, TextChannel textChannel, Long userId) {
|
||||
public CompletableFuture<Void> createPaginatorFromTemplate(String templateKey, Object model, GuildMessageChannel textChannel, Long userId) {
|
||||
Long serverId = textChannel.getGuild().getIdLong();
|
||||
String exitButtonId = componentService.generateComponentId(serverId);
|
||||
String startButtonId = componentService.generateComponentId(serverId);
|
||||
|
||||
@@ -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<Long> existingRoleIds = SnowflakeUtils.getOwnItemsIds(existingRoles);
|
||||
Set<Long> guildRoleIds = SnowflakeUtils.getSnowflakeIds(guildRoles);
|
||||
Set<Long> newRoles = SetUtils.difference(guildRoleIds, existingRoleIds);
|
||||
newRoles.forEach(aLong -> roleManagementService.createRole(aLong, existingAServer));
|
||||
newRoles.forEach(roleId -> roleManagementService.createRole(roleId, existingAServer));
|
||||
Set<Long> 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<GuildChannel> available = guild.getChannels();
|
||||
List<AChannel> knownChannels = existingServer.getChannels().stream().filter(aChannel -> !aChannel.getDeleted()).collect(Collectors.toList());
|
||||
List<AChannel> knownChannels = existingServer
|
||||
.getChannels()
|
||||
.stream()
|
||||
.filter(aChannel -> !aChannel.getDeleted())
|
||||
.filter(aChannel -> !aChannel.getType().isThread())
|
||||
.collect(Collectors.toList());
|
||||
Set<Long> knownChannelsIds = SnowflakeUtils.getOwnItemsIds(knownChannels);
|
||||
Set<Long> existingChannelsIds = SnowflakeUtils.getSnowflakeIds(available);
|
||||
Set<Long> 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<Long> noLongAvailable = SetUtils.difference(knownChannelsIds, existingChannelsIds);
|
||||
noLongAvailable.forEach(aLong ->
|
||||
channelManagementService.markAsDeleted(aLong)
|
||||
noLongAvailable.forEach(channelId ->
|
||||
channelManagementService.markAsDeleted(channelId)
|
||||
);
|
||||
List<ThreadChannel> availableThreads = new ArrayList<>();
|
||||
List<AChannel> 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<Long> knownThreadIds = SnowflakeUtils.getOwnItemsIds(knownThreads);
|
||||
Set<Long> existingThreadsIds = SnowflakeUtils.getSnowflakeIds(availableThreads);
|
||||
Set<Long> 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<Long> noLongAvailableThreads = SetUtils.difference(knownThreadIds, existingThreadsIds);
|
||||
noLongAvailableThreads.forEach(channelId ->
|
||||
channelManagementService.markAsDeleted(channelId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<AChannel> channelOptional = loadChannelOptional(id);
|
||||
return channelOptional.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
private AChannelCreatedListenerModel getCreationModel(AChannel channel) {
|
||||
return AChannelCreatedListenerModel
|
||||
.builder()
|
||||
|
||||
@@ -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
|
||||
@@ -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<MessageContextCommandListener> contextListeners = listenerBean.getListenerList();
|
||||
if(contextListeners == null || contextListeners.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
JDA jda = botService.getInstance();
|
||||
List<Guild> onlineGuilds = jda.getGuilds();
|
||||
onlineGuilds.forEach(guild -> {
|
||||
log.info("Updating commands for guild {}.", guild.getIdLong());
|
||||
guild.retrieveCommands().queue(commands -> {
|
||||
Map<String, Long> 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));
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
abstracto.startup.synchronize=true
|
||||
|
||||
abstracto.eventWaiter.threads=3
|
||||
server.port=8080
|
||||
|
||||
abstracto.allowedmention.everyone=false
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd">
|
||||
<include file="tables/tables.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<changeSet author="Sheldan" id="add-related-channel-column">
|
||||
<addColumn tableName="channel" >
|
||||
<column name="related_channel_id" type="BIGINT">
|
||||
<constraints nullable="true" />
|
||||
</column>
|
||||
</addColumn>
|
||||
<addForeignKeyConstraint baseColumnNames="related_channel_id" baseTableName="channel" constraintName="fk_channel_related_channel"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="id" referencedTableName="channel" validate="true"/>
|
||||
<sql>
|
||||
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'));
|
||||
</sql>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<changeSet author="Sheldan" id="remove-required-component-payload-server-id">
|
||||
<dropNotNullConstraint columnName="server_id" tableName="component_payload"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||
<include file="channel.xml" relativeToChangelogFile="true"/>
|
||||
<include file="component_payload.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -23,4 +23,5 @@
|
||||
<include file="1.3.9/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.3.10/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.3.13/collection.xml" relativeToChangelogFile="true"/>
|
||||
<include file="1.4.0/collection.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user