[AB-xxx] fixing combined parameters not providing the appropriate option types for slash commands

This commit is contained in:
Sheldan
2024-04-13 00:20:02 +02:00
parent 250df57bd0
commit dfe9792330
10 changed files with 125 additions and 12 deletions

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.entertainment.command; package dev.sheldan.abstracto.entertainment.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CombinedParameterEntry;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo; import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter; import dev.sheldan.abstracto.core.command.config.Parameter;
@@ -86,7 +87,7 @@ public class Mock extends AbstractConditionableCommand {
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
Map<String, Object> parameterAlternatives = new HashMap<>(); Map<String, Object> parameterAlternatives = new HashMap<>();
parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(Message.class, String.class)); parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(CombinedParameterEntry.messageParameter(Message.class), CombinedParameterEntry.parameter(String.class)));
Parameter messageParameter = Parameter Parameter messageParameter = Parameter
.builder() .builder()

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.imagegeneration.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition; import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CombinedParameterEntry;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo; import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter; import dev.sheldan.abstracto.core.command.config.Parameter;
@@ -115,7 +116,7 @@ public class Bonk extends AbstractConditionableCommand {
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
Map<String, Object> parameterAlternatives = new HashMap<>(); Map<String, Object> parameterAlternatives = new HashMap<>();
parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(Message.class, Member.class)); parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(CombinedParameterEntry.messageParameter(Message.class), CombinedParameterEntry.parameter(Member.class)));
Parameter memberParameter = Parameter Parameter memberParameter = Parameter
.builder() .builder()
.name(MEMBER_PARAMETER_KEY) .name(MEMBER_PARAMETER_KEY)

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.imagegeneration.command;
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition; import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CombinedParameterEntry;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo; import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter; import dev.sheldan.abstracto.core.command.config.Parameter;
@@ -115,7 +116,7 @@ public class Pat extends AbstractConditionableCommand {
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
Map<String, Object> parameterAlternatives = new HashMap<>(); Map<String, Object> parameterAlternatives = new HashMap<>();
parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(Message.class, Member.class)); parameterAlternatives.put(ADDITIONAL_TYPES_KEY, Arrays.asList(CombinedParameterEntry.messageParameter(Message.class), CombinedParameterEntry.parameter(Member.class)));
Parameter memberParameter = Parameter Parameter memberParameter = Parameter
.builder() .builder()
.name(MEMBER_PARAMETER_KEY) .name(MEMBER_PARAMETER_KEY)

View File

@@ -2,12 +2,12 @@ package dev.sheldan.abstracto.core.command.handler;
import dev.sheldan.abstracto.core.command.Command; import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.CommandConstants; import dev.sheldan.abstracto.core.command.CommandConstants;
import dev.sheldan.abstracto.core.command.config.CombinedParameterEntry;
import dev.sheldan.abstracto.core.command.config.Parameter; import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterException; import dev.sheldan.abstracto.core.command.exception.IncorrectParameterException;
import dev.sheldan.abstracto.core.command.execution.UnparsedCommandParameterPiece; import dev.sheldan.abstracto.core.command.execution.UnparsedCommandParameterPiece;
import dev.sheldan.abstracto.core.command.handler.parameter.CombinedParameter; import dev.sheldan.abstracto.core.command.handler.parameter.CombinedParameter;
import dev.sheldan.abstracto.core.command.handler.provided.CombinedParametersHandler; import dev.sheldan.abstracto.core.command.handler.provided.CombinedParametersHandler;
import dev.sheldan.abstracto.core.metric.service.MetricService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
@@ -28,9 +28,6 @@ public class CombinedParameterHandlerImpl implements CombinedParametersHandler {
@Lazy @Lazy
private List<CommandParameterHandler> parameterHandlers; private List<CommandParameterHandler> parameterHandlers;
@Autowired
private MetricService metricService;
@Override @Override
public boolean async() { public boolean async() {
return true; return true;
@@ -40,11 +37,16 @@ public class CombinedParameterHandlerImpl implements CombinedParametersHandler {
public CompletableFuture<Object> handleAsync(UnparsedCommandParameterPiece input, CommandParameterIterators iterators, Parameter param, Message context, Command command) { public CompletableFuture<Object> handleAsync(UnparsedCommandParameterPiece input, CommandParameterIterators iterators, Parameter param, Message context, Command command) {
List<CompletableFuture<Object>> futures = new ArrayList<>(); List<CompletableFuture<Object>> futures = new ArrayList<>();
CompletableFuture<Object> returningFuture = new CompletableFuture<>(); CompletableFuture<Object> returningFuture = new CompletableFuture<>();
List<Object> possibleTypes = (List) param.getAdditionalInfo().get(Parameter.ADDITIONAL_TYPES_KEY); List<CombinedParameterEntry> combinedParameterEntries = (List) param.getAdditionalInfo().get(Parameter.ADDITIONAL_TYPES_KEY);
for (Object concreteParameter: possibleTypes) { List<Class> possibleTypes = combinedParameterEntries
.stream()
.filter(CombinedParameterEntry::isUsableInMessageCommands)
.map(CombinedParameterEntry::getType)
.toList();
for (Class concreteParameter: possibleTypes) {
for (CommandParameterHandler handler : parameterHandlers) { for (CommandParameterHandler handler : parameterHandlers) {
try { try {
if (handler.handles((Class) concreteParameter, input)) { if (handler.handles(concreteParameter, input)) {
if (handler.async()) { if (handler.async()) {
futures.add(handler.handleAsync(input, iterators, param, context, command)); futures.add(handler.handleAsync(input, iterators, param, context, command));
} else { } else {

View File

@@ -119,7 +119,7 @@ public class SlashCommandServiceBean implements SlashCommandService {
if(!shouldParameterBeCreated(parameter, serverId)) { if(!shouldParameterBeCreated(parameter, serverId)) {
return; return;
} }
List<OptionType> types = slashCommandParameterService.getTypesFromParameter(parameter.getType()); List<OptionType> types = slashCommandParameterService.getTypesFromParameter(parameter);
if(types.size() > 1) { if(types.size() > 1) {
if(parameter.isListParam()) { if(parameter.isListParam()) {
for (int i = 0; i < parameter.getListSize(); i++) { for (int i = 0; i < parameter.getListSize(); i++) {

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.core.interaction.slash.parameter; package dev.sheldan.abstracto.core.interaction.slash.parameter;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.interaction.slash.parameter.provider.SlashCommandParameterProvider; import dev.sheldan.abstracto.core.interaction.slash.parameter.provider.SlashCommandParameterProvider;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AEmote;
@@ -151,6 +152,16 @@ public class SlashCommandParameterServiceBean implements SlashCommandParameterSe
return Emoji.fromFormatted(input); return Emoji.fromFormatted(input);
} }
@Override
public List<OptionType> getTypesFromParameter(Parameter parameter) {
return parameterProviders
.stream()
.filter(slashCommandParameterProvider -> slashCommandParameterProvider.getOptionMapping().getType().equals(parameter.getType()))
.findAny()
.map(slashCommandParameterProvider -> slashCommandParameterProvider.getOptionMapping(parameter).getOptionTypes())
.orElseThrow(() -> new IllegalArgumentException(String.format("Unknown type for slash command parameter desired %s", parameter.getType().getName())));
}
@Override @Override
public List<OptionType> getTypesFromParameter(Class clazz) { public List<OptionType> getTypesFromParameter(Class clazz) {
return parameterProviders return parameterProviders

View File

@@ -1,15 +1,25 @@
package dev.sheldan.abstracto.core.interaction.slash.parameter.provider.provided; package dev.sheldan.abstracto.core.interaction.slash.parameter.provider.provided;
import dev.sheldan.abstracto.core.command.config.CombinedParameterEntry;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.handler.parameter.CombinedParameter; import dev.sheldan.abstracto.core.command.handler.parameter.CombinedParameter;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandOptionTypeMapping; import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandOptionTypeMapping;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.interaction.slash.parameter.provider.SlashCommandParameterProvider; import dev.sheldan.abstracto.core.interaction.slash.parameter.provider.SlashCommandParameterProvider;
import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.OptionType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Arrays; import java.util.*;
import static dev.sheldan.abstracto.core.command.config.Parameter.ADDITIONAL_TYPES_KEY;
@Component @Component
public class CombinedSlashCommandParameterProvider implements SlashCommandParameterProvider { public class CombinedSlashCommandParameterProvider implements SlashCommandParameterProvider {
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Override @Override
public SlashCommandOptionTypeMapping getOptionMapping() { public SlashCommandOptionTypeMapping getOptionMapping() {
return SlashCommandOptionTypeMapping return SlashCommandOptionTypeMapping
@@ -18,4 +28,47 @@ public class CombinedSlashCommandParameterProvider implements SlashCommandParame
.optionTypes(Arrays.asList(OptionType.STRING)) .optionTypes(Arrays.asList(OptionType.STRING))
.build(); .build();
} }
/**
* The purpose of this method is just for the sake of a combined parameter, so that the combined parameters are evaluated _again_
* and every part of the parameter gets its own option. We only need this when creating the options. The other time a slash command parameter provider
* is executed, its when actually retrieving the parameter, but in that case the call is not done via the CombinedParameter type, but
* via the concrete type (Member, String, etc) anyway
*/
@Override
public SlashCommandOptionTypeMapping getOptionMapping(Parameter parameter) {
Map<String, Object> additionalInfo = parameter.getAdditionalInfo();
if(!additionalInfo.containsKey(ADDITIONAL_TYPES_KEY)) {
return empty();
}
List<CombinedParameterEntry> combinedParameterEntries = (List<CombinedParameterEntry>) additionalInfo.get(ADDITIONAL_TYPES_KEY);
if(combinedParameterEntries.isEmpty()) {
return empty();
}
List<Class> possibleTypes = combinedParameterEntries
.stream()
.filter(CombinedParameterEntry::isUsableInSlashCommands)
.map(CombinedParameterEntry::getType)
.toList();
if(possibleTypes.isEmpty()) {
return empty();
}
Set<OptionType> optionTypes = new HashSet<>();
possibleTypes.forEach(additionalType -> {
optionTypes.addAll(slashCommandParameterService.getTypesFromParameter(additionalType));
});
return SlashCommandOptionTypeMapping
.builder()
.type(CombinedParameter.class)
.optionTypes(new ArrayList<>(optionTypes))
.build();
}
private static SlashCommandOptionTypeMapping empty() {
return SlashCommandOptionTypeMapping
.builder()
.type(CombinedParameter.class)
.optionTypes(new ArrayList<>())
.build();
}
} }

View File

@@ -0,0 +1,37 @@
package dev.sheldan.abstracto.core.command.config;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class CombinedParameterEntry {
private Class type;
private boolean usableInSlashCommands;
private boolean usableInMessageCommands;
public static CombinedParameterEntry slashParameter(Class type) {
return CombinedParameterEntry
.builder()
.type(type)
.usableInSlashCommands(true)
.build();
}
public static CombinedParameterEntry messageParameter(Class type) {
return CombinedParameterEntry
.builder()
.type(type)
.usableInMessageCommands(true)
.build();
}
public static CombinedParameterEntry parameter(Class type) {
return CombinedParameterEntry
.builder()
.type(type)
.usableInMessageCommands(true)
.usableInSlashCommands(true)
.build();
}
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.interaction.slash.parameter; package dev.sheldan.abstracto.core.interaction.slash.parameter;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.models.database.AEmote; import dev.sheldan.abstracto.core.models.database.AEmote;
import net.dv8tion.jda.api.entities.emoji.Emoji; import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.interactions.commands.CommandInteractionPayload; import net.dv8tion.jda.api.interactions.commands.CommandInteractionPayload;
@@ -17,6 +18,7 @@ public interface SlashCommandParameterService {
Boolean hasCommandOptionWithFullType(String name, CommandInteractionPayload event, OptionType optionType); Boolean hasCommandOptionWithFullType(String name, CommandInteractionPayload event, OptionType optionType);
AEmote loadAEmoteFromString(String input, CommandInteractionPayload event); AEmote loadAEmoteFromString(String input, CommandInteractionPayload event);
Emoji loadEmoteFromString(String input, CommandInteractionPayload event); Emoji loadEmoteFromString(String input, CommandInteractionPayload event);
List<OptionType> getTypesFromParameter(Parameter parameter);
List<OptionType> getTypesFromParameter(Class clazz); List<OptionType> getTypesFromParameter(Class clazz);
String getFullQualifiedParameterName(String name, OptionType type); String getFullQualifiedParameterName(String name, OptionType type);
} }

View File

@@ -1,7 +1,12 @@
package dev.sheldan.abstracto.core.interaction.slash.parameter.provider; package dev.sheldan.abstracto.core.interaction.slash.parameter.provider;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandOptionTypeMapping; import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandOptionTypeMapping;
public interface SlashCommandParameterProvider { public interface SlashCommandParameterProvider {
SlashCommandOptionTypeMapping getOptionMapping(); SlashCommandOptionTypeMapping getOptionMapping();
default SlashCommandOptionTypeMapping getOptionMapping(Parameter parameter) {
return getOptionMapping();
}
} }