[AB-365] introducing slash commands for a selection of commands

adding method for pinning a message
moving suggestion to correct deployment
This commit is contained in:
Sheldan
2022-05-17 00:39:06 +02:00
parent 1913bc930d
commit 1d6de3f1e8
286 changed files with 8021 additions and 3065 deletions

View File

@@ -4,16 +4,21 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
import dev.sheldan.abstracto.entertainment.model.command.ChooseResponseModel; import dev.sheldan.abstracto.entertainment.model.command.ChooseResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService; import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -25,30 +30,81 @@ import java.util.concurrent.CompletableFuture;
public class Choose extends AbstractConditionableCommand { public class Choose extends AbstractConditionableCommand {
public static final String CHOOSE_RESPONSE_TEMPLATE_KEY = "choose_response"; public static final String CHOOSE_RESPONSE_TEMPLATE_KEY = "choose_response";
private static final String CHOOSE_COMMAND = "choose";
private static final String TEXT_PARAMETER = "text";
private static final int CHOICES_SIZE = 5;
@Autowired @Autowired
private EntertainmentService entertainmentService; private EntertainmentService entertainmentService;
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<String> choices = (List) commandContext.getParameters().getParameters().get(0); List<String> choices = (List) commandContext.getParameters().getParameters().get(0);
String choice = entertainmentService.takeChoice(choices, commandContext.getAuthor()); String choice = entertainmentService.takeChoice(choices, commandContext.getAuthor());
ChooseResponseModel responseModel = (ChooseResponseModel) ContextConverter.slimFromCommandContext(commandContext, ChooseResponseModel.class); ChooseResponseModel responseModel = ChooseResponseModel
responseModel.setChosenValue(choice); .builder()
.chosenValue(choice)
.build();
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(CHOOSE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel())) return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(CHOOSE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored()); .thenApply(unused -> CommandResult.fromIgnored());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
List<String> choices = new ArrayList<>();
for (int i = 0; i < CHOICES_SIZE; i++) {
if(slashCommandParameterService.hasCommandOption(TEXT_PARAMETER + "_" + i, event)) {
String choice = slashCommandParameterService.getCommandOption(TEXT_PARAMETER + "_" + i, event, String.class);
choices.add(choice);
}
}
String choice = entertainmentService.takeChoice(choices, event.getMember());
ChooseResponseModel responseModel = ChooseResponseModel
.builder()
.chosenValue(choice)
.build();
return interactionService.replyEmbed(CHOOSE_RESPONSE_TEMPLATE_KEY, responseModel, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("text").type(String.class).templated(true).remainder(true).isListParam(true).build()); Parameter textParameter = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(TEXT_PARAMETER)
.type(String.class)
.templated(true)
.remainder(true)
.listSize(CHOICES_SIZE)
.isListParam(true)
.build();
parameters.add(textParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
.commandName(CHOOSE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("choose") .name(CHOOSE_COMMAND)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.module(EntertainmentModuleDefinition.ENTERTAINMENT) .module(EntertainmentModuleDefinition.ENTERTAINMENT)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -4,17 +4,23 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
import dev.sheldan.abstracto.entertainment.model.command.EightBallResponseModel; import dev.sheldan.abstracto.entertainment.model.command.EightBallResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService; import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -26,6 +32,8 @@ import java.util.concurrent.CompletableFuture;
public class EightBall extends AbstractConditionableCommand { public class EightBall extends AbstractConditionableCommand {
public static final String EIGHT_BALL_RESPONSE_TEMPLATE_KEY = "eight_ball_response"; public static final String EIGHT_BALL_RESPONSE_TEMPLATE_KEY = "eight_ball_response";
public static final String BALL_COMMAND = "8Ball";
public static final String TEXT_PARAMETER = "text";
@Autowired @Autowired
private EntertainmentService entertainmentService; private EntertainmentService entertainmentService;
@@ -35,24 +43,65 @@ public class EightBall extends AbstractConditionableCommand {
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
String text = (String) commandContext.getParameters().getParameters().get(0); String text = (String) commandContext.getParameters().getParameters().get(0);
String chosenKey = entertainmentService.getEightBallValue(text); MessageToSend messageToSend = getMessageToSend(text, commandContext.getGuild().getIdLong());
EightBallResponseModel responseModel = (EightBallResponseModel) ContextConverter.slimFromCommandContext(commandContext, EightBallResponseModel.class); return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
responseModel.setChosenKey(chosenKey);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(EIGHT_BALL_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored()); .thenApply(unused -> CommandResult.fromIgnored());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String text = slashCommandParameterService.getCommandOption(TEXT_PARAMETER, event, String.class);
MessageToSend messageToSend = getMessageToSend(text, event.getGuild().getIdLong());
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
private MessageToSend getMessageToSend(String text, Long serverId) {
String chosenKey = entertainmentService.getEightBallValue(text);
EightBallResponseModel responseModel = EightBallResponseModel
.builder()
.chosenKey(chosenKey)
.build();
return templateService.renderEmbedTemplate(EIGHT_BALL_RESPONSE_TEMPLATE_KEY, responseModel, serverId);
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("text").type(String.class).templated(true).remainder(true).build()); Parameter textParameter = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(TEXT_PARAMETER)
.type(String.class)
.templated(true)
.remainder(true)
.build();
parameters.add(textParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
.commandName(BALL_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("8Ball") .name(BALL_COMMAND)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.module(EntertainmentModuleDefinition.ENTERTAINMENT) .module(EntertainmentModuleDefinition.ENTERTAINMENT)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -4,16 +4,23 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
import dev.sheldan.abstracto.entertainment.model.command.LoveCalcResponseModel; import dev.sheldan.abstracto.entertainment.model.command.LoveCalcResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService; import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -25,6 +32,9 @@ import java.util.concurrent.CompletableFuture;
public class LoveCalc extends AbstractConditionableCommand { public class LoveCalc extends AbstractConditionableCommand {
public static final String LOVE_CALC_RESPONSE_TEMPLATE_KEY = "loveCalc_response"; public static final String LOVE_CALC_RESPONSE_TEMPLATE_KEY = "loveCalc_response";
public static final String FIRST_SUBJECT_PARAMETER = "firstSubject";
public static final String SECOND_SUBJECT_PARAMETER = "secondSubject";
public static final String LOVE_CALC_COMMAND = "loveCalc";
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@@ -32,28 +42,77 @@ public class LoveCalc extends AbstractConditionableCommand {
@Autowired @Autowired
private EntertainmentService entertainmentService; private EntertainmentService entertainmentService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Autowired
private TemplateService templateService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
String firstPart = (String) parameters.get(0); String firstPart = (String) parameters.get(0);
String secondPart = (String) parameters.get(1); String secondPart = (String) parameters.get(1);
Integer rolled = entertainmentService.getLoveCalcValue(firstPart, secondPart); MessageToSend messageToSend = getMessageToSend(commandContext.getGuild().getIdLong(), firstPart, secondPart);
LoveCalcResponseModel model = (LoveCalcResponseModel) ContextConverter.slimFromCommandContext(commandContext, LoveCalcResponseModel.class); return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
model.setRolled(rolled);
model.setFirstPart(firstPart);
model.setSecondPart(secondPart);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(LOVE_CALC_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromSuccess()); .thenApply(unused -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String firstPart = slashCommandParameterService.getCommandOption(FIRST_SUBJECT_PARAMETER, event, String.class);
String secondPart = slashCommandParameterService.getCommandOption(SECOND_SUBJECT_PARAMETER, event, String.class);
MessageToSend messageToSend = getMessageToSend(event.getGuild().getIdLong(), firstPart, secondPart);
return interactionService.replyMessageToSend(messageToSend, event.getInteraction())
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
private MessageToSend getMessageToSend(Long serverId, String firstPart, String secondPart) {
Integer rolled = entertainmentService.getLoveCalcValue(firstPart, secondPart);
LoveCalcResponseModel model = LoveCalcResponseModel
.builder()
.rolled(rolled)
.firstPart(firstPart)
.secondPart(secondPart)
.build();
return templateService.renderEmbedTemplate(LOVE_CALC_RESPONSE_TEMPLATE_KEY, model, serverId);
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("firstSubject").type(String.class).templated(true).build()); Parameter firstSubjectParameter = Parameter
parameters.add(Parameter.builder().name("secondSubject").type(String.class).templated(true).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .name(FIRST_SUBJECT_PARAMETER)
.type(String.class)
.templated(true)
.build();
parameters.add(firstSubjectParameter);
Parameter secondSubjectParameter = Parameter
.builder()
.name(SECOND_SUBJECT_PARAMETER)
.type(String.class)
.templated(true)
.build();
parameters.add(secondSubjectParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
.commandName(LOVE_CALC_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("loveCalc") .name(LOVE_CALC_COMMAND)
.slashCommandConfig(slashCommandConfig)
.async(true) .async(true)
.module(EntertainmentModuleDefinition.ENTERTAINMENT) .module(EntertainmentModuleDefinition.ENTERTAINMENT)
.templated(true) .templated(true)

View File

@@ -4,19 +4,23 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator; import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.ConfigService; import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig; import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
import dev.sheldan.abstracto.entertainment.model.command.RollResponseModel; import dev.sheldan.abstracto.entertainment.model.command.RollResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService; import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -29,6 +33,9 @@ import java.util.concurrent.CompletableFuture;
public class Roll extends AbstractConditionableCommand { public class Roll extends AbstractConditionableCommand {
public static final String ROLL_RESPONSE_TEMPLATE_KEY = "roll_response"; public static final String ROLL_RESPONSE_TEMPLATE_KEY = "roll_response";
private static final String ROLL_COMMAND = "roll";
private static final String LOW_PARAMETER = "low";
private static final String HIGH_PARAMETER = "high";
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@@ -39,6 +46,12 @@ public class Roll extends AbstractConditionableCommand {
@Autowired @Autowired
private ConfigService configService; private ConfigService configService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
@@ -52,20 +65,73 @@ public class Roll extends AbstractConditionableCommand {
} }
Integer rolled = entertainmentService.calculateRollResult(low, high); Integer rolled = entertainmentService.calculateRollResult(low, high);
RollResponseModel model = (RollResponseModel) ContextConverter.slimFromCommandContext(commandContext, RollResponseModel.class); RollResponseModel model = RollResponseModel
model.setRolled(rolled); .builder()
.rolled(rolled)
.build();
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ROLL_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel())) return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ROLL_RESPONSE_TEMPLATE_KEY, model, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored()); .thenApply(unused -> CommandResult.fromIgnored());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Integer low;
if(slashCommandParameterService.hasCommandOption(LOW_PARAMETER, event)) {
low = slashCommandParameterService.getCommandOption(LOW_PARAMETER, event, Integer.class);
} else {
low = 1;
}
Integer high;
if(slashCommandParameterService.hasCommandOption(HIGH_PARAMETER, event)) {
high = slashCommandParameterService.getCommandOption(HIGH_PARAMETER, event, Integer.class);
} else {
high = configService.getLongValueOrConfigDefault(EntertainmentFeatureConfig.ROLL_DEFAULT_HIGH_KEY, event.getGuild().getIdLong()).intValue();
}
Integer rolled = entertainmentService.calculateRollResult(low, high);
RollResponseModel model = RollResponseModel
.builder()
.rolled(rolled)
.build();
return interactionService.replyEmbed(ROLL_RESPONSE_TEMPLATE_KEY, model, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("high").type(Integer.class).templated(true).validators(Arrays.asList(MinIntegerValueValidator.min(2L))).optional(true).build()); Parameter highParameter = Parameter
parameters.add(Parameter.builder().name("low").type(Integer.class).templated(true).validators(Arrays.asList(MinIntegerValueValidator.min(0L))).optional(true).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .name(HIGH_PARAMETER)
.type(Integer.class)
.templated(true)
.validators(Arrays.asList(MinIntegerValueValidator.min(2L)))
.optional(true)
.build();
parameters.add(highParameter);
Parameter lowParameter = Parameter
.builder()
.name(LOW_PARAMETER)
.type(Integer.class)
.templated(true)
.validators(Arrays.asList(MinIntegerValueValidator.min(0L)))
.optional(true)
.build();
parameters.add(lowParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
.commandName(ROLL_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("roll") .name(ROLL_COMMAND)
.slashCommandConfig(slashCommandConfig)
.async(true) .async(true)
.module(EntertainmentModuleDefinition.ENTERTAINMENT) .module(EntertainmentModuleDefinition.ENTERTAINMENT)
.templated(true) .templated(true)

View File

@@ -4,16 +4,19 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition; import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition;
import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames;
import dev.sheldan.abstracto.entertainment.model.command.RouletteResponseModel; import dev.sheldan.abstracto.entertainment.model.command.RouletteResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService; import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -25,28 +28,57 @@ import java.util.concurrent.CompletableFuture;
public class Roulette extends AbstractConditionableCommand { public class Roulette extends AbstractConditionableCommand {
public static final String ROULETTE_RESPONSE_TEMPLATE_KEY = "roulette_response"; public static final String ROULETTE_RESPONSE_TEMPLATE_KEY = "roulette_response";
public static final String ROULETTE_COMMAND = "roulette";
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@Autowired @Autowired
private EntertainmentService entertainmentService; private EntertainmentService entertainmentService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
boolean rouletteResult = entertainmentService.executeRoulette(commandContext.getAuthor()); boolean rouletteResult = entertainmentService.executeRoulette(commandContext.getAuthor());
RouletteResponseModel responseModel = (RouletteResponseModel) ContextConverter.slimFromCommandContext(commandContext, RouletteResponseModel.class); RouletteResponseModel responseModel = RouletteResponseModel
responseModel.setResult(rouletteResult); .builder()
.result(rouletteResult)
.build();
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ROULETTE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel())) return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(ROULETTE_RESPONSE_TEMPLATE_KEY, responseModel, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored()); .thenApply(unused -> CommandResult.fromIgnored());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
boolean rouletteResult = entertainmentService.executeRoulette(event.getMember());
RouletteResponseModel responseModel = RouletteResponseModel
.builder()
.result(rouletteResult)
.build();
return interactionService.replyEmbed(ROULETTE_RESPONSE_TEMPLATE_KEY, responseModel, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(EntertainmentSlashCommandNames.UTILITY)
.commandName(ROULETTE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("roulette") .name(ROULETTE_COMMAND)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.module(EntertainmentModuleDefinition.ENTERTAINMENT) .module(EntertainmentModuleDefinition.ENTERTAINMENT)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -1,56 +0,0 @@
package dev.sheldan.abstracto.entertainment.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.command.ChooseResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ChooseTest {
@InjectMocks
private Choose testUnit;
@Mock
private EntertainmentService entertainmentService;
@Mock
private ChannelService channelService;
@Captor
private ArgumentCaptor<ChooseResponseModel> responseModelArgumentCaptor;
@Test
public void executeChooseCommand() {
List<String> choices = Arrays.asList("choice1", "choice2");
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(choices));
when(entertainmentService.takeChoice(choices, parameters.getAuthor())).thenReturn(choices.get(0));
when(channelService.sendEmbedTemplateInTextChannelList(eq(Choose.CHOOSE_RESPONSE_TEMPLATE_KEY), responseModelArgumentCaptor.capture(), eq(parameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
Assert.assertEquals(choices.get(0), responseModelArgumentCaptor.getValue().getChosenValue());
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,57 +0,0 @@
package dev.sheldan.abstracto.entertainment.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.command.EightBallResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class EightBallTest {
@InjectMocks
private EightBall testUnit;
@Mock
private EntertainmentService entertainmentService;
@Mock
private ChannelService channelService;
@Captor
private ArgumentCaptor<EightBallResponseModel> responseModelArgumentCaptor;
@Test
public void execute8BallCommand() {
String inputText = "text";
String chosenKey = "key";
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(inputText));
when(entertainmentService.getEightBallValue(inputText)).thenReturn(chosenKey);
when(channelService.sendEmbedTemplateInTextChannelList(eq(EightBall.EIGHT_BALL_RESPONSE_TEMPLATE_KEY), responseModelArgumentCaptor.capture(), eq(parameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
Assert.assertEquals(chosenKey, responseModelArgumentCaptor.getValue().getChosenKey());
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,61 +0,0 @@
package dev.sheldan.abstracto.entertainment.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.command.LoveCalcResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static dev.sheldan.abstracto.entertainment.command.LoveCalc.LOVE_CALC_RESPONSE_TEMPLATE_KEY;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class LoveCalcTest {
@InjectMocks
private LoveCalc testUnit;
@Mock
private EntertainmentService entertainmentService;
@Mock
private ChannelService channelService;
@Captor
private ArgumentCaptor<LoveCalcResponseModel> responseModelArgumentCaptor;
@Test
public void execute8BallCommand() {
String inputText = "text";
String inputText2 = "text2";
Integer loveResult = 2;
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(inputText, inputText2));
when(entertainmentService.getLoveCalcValue(inputText, inputText2)).thenReturn(loveResult);
when(channelService.sendEmbedTemplateInTextChannelList(eq(LOVE_CALC_RESPONSE_TEMPLATE_KEY), responseModelArgumentCaptor.capture(), eq(parameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
Assert.assertEquals(loveResult, responseModelArgumentCaptor.getValue().getRolled());
Assert.assertEquals(inputText, responseModelArgumentCaptor.getValue().getFirstPart());
Assert.assertEquals(inputText2, responseModelArgumentCaptor.getValue().getSecondPart());
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,87 +0,0 @@
package dev.sheldan.abstracto.entertainment.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.command.RollResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig.ROLL_DEFAULT_HIGH_KEY;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class RollTest {
@InjectMocks
private Roll testUnit;
@Mock
private EntertainmentService entertainmentService;
@Mock
private ChannelService channelService;
@Mock
private ConfigService configService;
@Captor
private ArgumentCaptor<RollResponseModel> responseModelArgumentCaptor;
@Test
public void executeWithNoParameter() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
Integer result = 4;
Long serverId = 3L;
Integer max = 10;
when(noParameters.getGuild().getIdLong()).thenReturn(serverId);
when(configService.getLongValueOrConfigDefault(ROLL_DEFAULT_HIGH_KEY, serverId)).thenReturn(max.longValue());
when(entertainmentService.calculateRollResult(1, max)).thenReturn(result);
when(channelService.sendEmbedTemplateInTextChannelList(eq(Roll.ROLL_RESPONSE_TEMPLATE_KEY), responseModelArgumentCaptor.capture(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> futureResult = testUnit.executeAsync(noParameters);
CommandTestUtilities.checkSuccessfulCompletionAsync(futureResult);
Assert.assertEquals(4, responseModelArgumentCaptor.getValue().getRolled().intValue());
}
@Test
public void executeWithHighParameter() {
CommandContext noParameters = CommandTestUtilities.getWithParameters(Arrays.asList(20));
Integer result = 4;
when(entertainmentService.calculateRollResult(1, 20)).thenReturn(result);
when(channelService.sendEmbedTemplateInTextChannelList(eq(Roll.ROLL_RESPONSE_TEMPLATE_KEY), responseModelArgumentCaptor.capture(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> futureResult = testUnit.executeAsync(noParameters);
CommandTestUtilities.checkSuccessfulCompletionAsync(futureResult);
Assert.assertEquals(4, responseModelArgumentCaptor.getValue().getRolled().intValue());
}
@Test
public void executeWithBothParameters() {
CommandContext noParameters = CommandTestUtilities.getWithParameters(Arrays.asList(20, 10));
Integer result = 4;
when(entertainmentService.calculateRollResult(10, 20)).thenReturn(result);
when(channelService.sendEmbedTemplateInTextChannelList(eq(Roll.ROLL_RESPONSE_TEMPLATE_KEY), responseModelArgumentCaptor.capture(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> futureResult = testUnit.executeAsync(noParameters);
CommandTestUtilities.checkSuccessfulCompletionAsync(futureResult);
Assert.assertEquals(4, responseModelArgumentCaptor.getValue().getRolled().intValue());
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,55 +0,0 @@
package dev.sheldan.abstracto.entertainment.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.entertainment.model.command.RouletteResponseModel;
import dev.sheldan.abstracto.entertainment.service.EntertainmentService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.concurrent.CompletableFuture;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class RouletteTest {
@InjectMocks
private Roulette testUnit;
@Mock
private EntertainmentService entertainmentService;
@Mock
private ChannelService channelService;
@Captor
private ArgumentCaptor<RouletteResponseModel> responseModelArgumentCaptor;
@Test
public void executeWithNoParameter() {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
Boolean result = false;
when(entertainmentService.executeRoulette(noParameters.getAuthor())).thenReturn(result);
when(channelService.sendEmbedTemplateInTextChannelList(eq(Roulette.ROULETTE_RESPONSE_TEMPLATE_KEY), responseModelArgumentCaptor.capture(), eq(noParameters.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> futureResult = testUnit.executeAsync(noParameters);
CommandTestUtilities.checkSuccessfulCompletionAsync(futureResult);
Assert.assertEquals(result, responseModelArgumentCaptor.getValue().getResult());
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.entertainment.config;
public class EntertainmentSlashCommandNames {
public static final String ENTERTAINMENT = "entertainment";
public static final String UTILITY = "utility";
}

View File

@@ -1,13 +1,12 @@
package dev.sheldan.abstracto.entertainment.model.command; package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder;
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class ChooseResponseModel extends SlimUserInitiatedServerContext { public class ChooseResponseModel {
private String chosenValue; private String chosenValue;
} }

View File

@@ -1,13 +1,12 @@
package dev.sheldan.abstracto.entertainment.model.command; package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder;
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class EightBallResponseModel extends SlimUserInitiatedServerContext { public class EightBallResponseModel {
private String chosenKey; private String chosenKey;
} }

View File

@@ -1,14 +1,13 @@
package dev.sheldan.abstracto.entertainment.model.command; package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder;
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class LoveCalcResponseModel extends SlimUserInitiatedServerContext { public class LoveCalcResponseModel {
private String firstPart; private String firstPart;
private String secondPart; private String secondPart;
private Integer rolled; private Integer rolled;

View File

@@ -1,13 +1,12 @@
package dev.sheldan.abstracto.entertainment.model.command; package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder;
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class RollResponseModel extends SlimUserInitiatedServerContext { public class RollResponseModel {
private Integer rolled; private Integer rolled;
} }

View File

@@ -1,13 +1,12 @@
package dev.sheldan.abstracto.entertainment.model.command; package dev.sheldan.abstracto.entertainment.model.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder;
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class RouletteResponseModel extends SlimUserInitiatedServerContext { public class RouletteResponseModel {
private Boolean result; private Boolean result;
} }

View File

@@ -4,19 +4,26 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.ARole; import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.management.RoleManagementService; import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition; import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
import dev.sheldan.abstracto.experience.service.management.DisabledExpRoleManagementService; import dev.sheldan.abstracto.experience.service.management.DisabledExpRoleManagementService;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
/** /**
* Command used to add a role to the roles for which experience has been disabled. * Command used to add a role to the roles for which experience has been disabled.
@@ -24,21 +31,31 @@ import java.util.List;
@Component @Component
public class DisableExpForRole extends AbstractConditionableCommand { public class DisableExpForRole extends AbstractConditionableCommand {
private static final String DISABLE_EXP_FOR_ROLE_COMMAND = "disableExpForRole";
private static final String DISABLE_EXP_FOR_ROLE_RESPONSE = "disableExpForRole_response";
private static final String ROLE_PARAMETER = "role";
@Autowired @Autowired
private DisabledExpRoleManagementService disabledExpRoleManagementService; private DisabledExpRoleManagementService disabledExpRoleManagementService;
@Autowired @Autowired
private RoleManagementService roleManagementService; private RoleManagementService roleManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
ARole role = (ARole) parameters.get(0); Role role = (Role) parameters.get(0);
ARole actualRole = roleManagementService.findRole(role.getId()); ARole actualRole = roleManagementService.findRole(role.getIdLong());
if(!actualRole.getServer().getId().equals(commandContext.getGuild().getIdLong())) { if(!actualRole.getServer().getId().equals(commandContext.getGuild().getIdLong())) {
throw new EntityGuildMismatchException(); throw new EntityGuildMismatchException();
} }
// as we mange experience disabled roles via the existence of them in a table, we should not do anything // as we manage experience disabled roles via the existence of them in a table, we should not do anything
// in case it is used a second time as a disabled experience role // in case it is used a second time as a disabled experience role
if(!disabledExpRoleManagementService.isExperienceDisabledForRole(actualRole)) { if(!disabledExpRoleManagementService.isExperienceDisabledForRole(actualRole)) {
disabledExpRoleManagementService.setRoleToBeDisabledForExp(actualRole); disabledExpRoleManagementService.setRoleToBeDisabledForExp(actualRole);
@@ -46,15 +63,48 @@ public class DisableExpForRole extends AbstractConditionableCommand {
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Role role = slashCommandParameterService.getCommandOption(ROLE_PARAMETER, event, Role.class);
ARole actualRole = roleManagementService.findRole(role.getIdLong());
if(!actualRole.getServer().getId().equals(event.getGuild().getIdLong())) {
throw new EntityGuildMismatchException();
}
// as we manage experience disabled roles via the existence of them in a table, we should not do anything
// in case it is used a second time as a disabled experience role
if(!disabledExpRoleManagementService.isExperienceDisabledForRole(actualRole)) {
disabledExpRoleManagementService.setRoleToBeDisabledForExp(actualRole);
}
return interactionService.replyEmbed(DISABLE_EXP_FOR_ROLE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter roleParameter = Parameter
parameters.add(Parameter.builder().name("role").templated(true).type(ARole.class).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .name(ROLE_PARAMETER)
.templated(true)
.type(Role.class)
.build();
List<Parameter> parameters = Arrays.asList(roleParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE_CONFIG)
.commandName(DISABLE_EXP_FOR_ROLE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("disableExpForRole") .name(DISABLE_EXP_FOR_ROLE_COMMAND)
.module(ExperienceModuleDefinition.EXPERIENCE) .module(ExperienceModuleDefinition.EXPERIENCE)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)
.parameters(parameters) .parameters(parameters)

View File

@@ -4,20 +4,26 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition; import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
import dev.sheldan.abstracto.experience.service.AUserExperienceService; import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
/** /**
* Command used to disable the experience gain for a specific member * Command used to disable the experience gain for a specific member
@@ -25,12 +31,21 @@ import java.util.List;
@Component @Component
public class DisableExpGain extends AbstractConditionableCommand { public class DisableExpGain extends AbstractConditionableCommand {
private static final String MEMBER_PARAMETER = "member";
private static final String DISABLE_EXP_GAIN_COMMAND = "disableExpGain";
private static final String DISABLE_EXP_GAIN_RESPONSE = "disableExpGain_response";
@Autowired @Autowired
private AUserExperienceService aUserExperienceService; private AUserExperienceService aUserExperienceService;
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
Member para = (Member) commandContext.getParameters().getParameters().get(0); Member para = (Member) commandContext.getParameters().getParameters().get(0);
@@ -42,14 +57,43 @@ public class DisableExpGain extends AbstractConditionableCommand {
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member para = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER, event, Member.class);
if(!para.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(para);
aUserExperienceService.disableExperienceForUser(userInAServer);
return interactionService.replyEmbed(DISABLE_EXP_GAIN_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter memberParameter = Parameter
parameters.add(Parameter.builder().name("member").templated(true).type(Member.class).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .name(MEMBER_PARAMETER)
.templated(true)
.type(Member.class)
.build();
List<Parameter> parameters = Arrays.asList(memberParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE_CONFIG)
.commandName(DISABLE_EXP_GAIN_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("disableExpGain") .name(DISABLE_EXP_GAIN_COMMAND)
.module(ExperienceModuleDefinition.EXPERIENCE) .module(ExperienceModuleDefinition.EXPERIENCE)
.slashCommandConfig(slashCommandConfig)
.causesReaction(true) .causesReaction(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.templated(true) .templated(true)

View File

@@ -4,19 +4,28 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.exception.SlashCommandParameterMissingException;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.ARole; import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.management.RoleManagementService; import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition; import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
import dev.sheldan.abstracto.experience.service.management.DisabledExpRoleManagementService; import dev.sheldan.abstracto.experience.service.management.DisabledExpRoleManagementService;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
/** /**
* Command used to remove a role from the list of roles for which experience is disabled * Command used to remove a role from the list of roles for which experience is disabled
@@ -24,12 +33,22 @@ import java.util.List;
@Component @Component
public class EnableExpForRole extends AbstractConditionableCommand { public class EnableExpForRole extends AbstractConditionableCommand {
private static final String ENABLE_EXP_FOR_ROLE_COMMAND = "enableExpForRole";
private static final String ENABLE_EXP_FOR_ROLE_RESPONSE = "enableExpForRole_response";
private static final String ROLE_PARAMETER = "role";
@Autowired @Autowired
private DisabledExpRoleManagementService disabledExpRoleManagementService; private DisabledExpRoleManagementService disabledExpRoleManagementService;
@Autowired @Autowired
private RoleManagementService roleManagementService; private RoleManagementService roleManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
ARole role = (ARole) commandContext.getParameters().getParameters().get(0); ARole role = (ARole) commandContext.getParameters().getParameters().get(0);
@@ -44,15 +63,51 @@ public class EnableExpForRole extends AbstractConditionableCommand {
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
ARole actualRole;
if(slashCommandParameterService.hasCommandOptionWithFullType(ROLE_PARAMETER, event, OptionType.ROLE)) {
Role role = slashCommandParameterService.getCommandOption(ROLE_PARAMETER, event, ARole.class, Role.class);
actualRole = roleManagementService.findRole(role.getIdLong());
} else if(slashCommandParameterService.hasCommandOptionWithFullType(ROLE_PARAMETER, event, OptionType.STRING)) {
String roleId = slashCommandParameterService.getCommandOption(ROLE_PARAMETER, event, ARole.class, String.class);
actualRole = roleManagementService.findRole(Long.parseLong(roleId));
} else {
throw new SlashCommandParameterMissingException(ROLE_PARAMETER);
}
if(disabledExpRoleManagementService.isExperienceDisabledForRole(actualRole)) {
disabledExpRoleManagementService.removeRoleToBeDisabledForExp(actualRole);
}
return interactionService.replyEmbed(ENABLE_EXP_FOR_ROLE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter roleParameter = Parameter
parameters.add(Parameter.builder().name("role").templated(true).type(ARole.class).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .name(ROLE_PARAMETER)
.templated(true)
.type(ARole.class)
.build();
List<Parameter> parameters = Arrays.asList(roleParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE_CONFIG)
.commandName(ENABLE_EXP_FOR_ROLE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("enableExpForRole") .name(ENABLE_EXP_FOR_ROLE_COMMAND)
.module(ExperienceModuleDefinition.EXPERIENCE) .module(ExperienceModuleDefinition.EXPERIENCE)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.causesReaction(true) .causesReaction(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.parameters(parameters) .parameters(parameters)

View File

@@ -4,20 +4,26 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition; import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
import dev.sheldan.abstracto.experience.service.AUserExperienceService; import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
/** /**
* Command to enable experience gain for a member * Command to enable experience gain for a member
@@ -25,30 +31,69 @@ import java.util.List;
@Component @Component
public class EnableExpGain extends AbstractConditionableCommand { public class EnableExpGain extends AbstractConditionableCommand {
private static final String ENABLE_EXP_GAIN_COMMAND = "enableExpGain";
private static final String ENABLE_EXP_GAIN_RESPONSE = "enableExpGain_response";
private static final String MEMBER_PARAMETER = "member";
@Autowired @Autowired
private AUserExperienceService aUserExperienceService; private AUserExperienceService aUserExperienceService;
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
Member para = (Member) commandContext.getParameters().getParameters().get(0); Member member = (Member) commandContext.getParameters().getParameters().get(0);
if(!para.getGuild().equals(commandContext.getGuild())) { if(!member.getGuild().equals(commandContext.getGuild())) {
throw new EntityGuildMismatchException(); throw new EntityGuildMismatchException();
} }
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(para); AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(member);
aUserExperienceService.enableExperienceForUser(userInAServer); aUserExperienceService.enableExperienceForUser(userInAServer);
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member member = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER, event, Member.class);
if(!member.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(member);
aUserExperienceService.enableExperienceForUser(userInAServer);
return interactionService.replyEmbed(ENABLE_EXP_GAIN_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter memberParameter = Parameter
parameters.add(Parameter.builder().name("member").templated(true).type(Member.class).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .name(MEMBER_PARAMETER)
.templated(true)
.type(Member.class)
.build();
List<Parameter> parameters = Arrays.asList(memberParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE_CONFIG)
.commandName(ENABLE_EXP_GAIN_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("enableExpGain") .name(ENABLE_EXP_GAIN_COMMAND)
.slashCommandConfig(slashCommandConfig)
.module(ExperienceModuleDefinition.EXPERIENCE) .module(ExperienceModuleDefinition.EXPERIENCE)
.causesReaction(true) .causesReaction(true)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -4,18 +4,24 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.ConfigService; import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition; import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureConfig; import dev.sheldan.abstracto.experience.config.ExperienceFeatureConfig;
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
/** /**
@@ -25,9 +31,19 @@ import java.util.List;
@Slf4j @Slf4j
public class ExpScale extends AbstractConditionableCommand { public class ExpScale extends AbstractConditionableCommand {
private static final String EXP_SCALE_COMMAND = "expScale";
private static final String EXP_SCALE_RESPONSE = "expScale_response";
private static final String SCALE_PARAMETER = "scale";
@Autowired @Autowired
private ConfigService configService; private ConfigService configService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
Double scale = (Double) commandContext.getParameters().getParameters().get(0); Double scale = (Double) commandContext.getParameters().getParameters().get(0);
@@ -37,15 +53,42 @@ public class ExpScale extends AbstractConditionableCommand {
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Double newScale = slashCommandParameterService.getCommandOption(SCALE_PARAMETER, event, Double.class);
configService.setDoubleValue(ExperienceFeatureConfig.EXP_MULTIPLIER_KEY, event.getGuild().getIdLong(), newScale);
return interactionService.replyEmbed(EXP_SCALE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("scale").templated(true).type(Double.class).build()); Parameter newScale = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(SCALE_PARAMETER)
.templated(true)
.type(Double.class)
.build();
parameters.add(newScale);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE_CONFIG)
.commandName(EXP_SCALE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("expScale") .name(EXP_SCALE_COMMAND)
.module(ExperienceModuleDefinition.EXPERIENCE) .module(ExperienceModuleDefinition.EXPERIENCE)
.causesReaction(true) .causesReaction(true)
.slashCommandConfig(slashCommandConfig)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.parameters(parameters) .parameters(parameters)

View File

@@ -1,15 +1,13 @@
package dev.sheldan.abstracto.experience.command; package dev.sheldan.abstracto.experience.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.ParameterValidator;
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator; import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
@@ -17,6 +15,7 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition; import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
import dev.sheldan.abstracto.experience.converter.LeaderBoardModelConverter; import dev.sheldan.abstracto.experience.converter.LeaderBoardModelConverter;
import dev.sheldan.abstracto.experience.model.LeaderBoard; import dev.sheldan.abstracto.experience.model.LeaderBoard;
import dev.sheldan.abstracto.experience.model.LeaderBoardEntry; import dev.sheldan.abstracto.experience.model.LeaderBoardEntry;
@@ -26,6 +25,8 @@ import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -42,6 +43,8 @@ import java.util.concurrent.CompletableFuture;
public class LeaderBoardCommand extends AbstractConditionableCommand { public class LeaderBoardCommand extends AbstractConditionableCommand {
public static final String LEADER_BOARD_POST_EMBED_TEMPLATE = "leaderboard_post"; public static final String LEADER_BOARD_POST_EMBED_TEMPLATE = "leaderboard_post";
private static final String LEADERBOARD_PARAMTER = "leaderboard";
private static final String PAGE_PARAMETER = "page";
@Autowired @Autowired
private AUserExperienceService userExperienceService; private AUserExperienceService userExperienceService;
@@ -60,43 +63,89 @@ public class LeaderBoardCommand extends AbstractConditionableCommand {
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
// parameter is optional, in case its not present, we default to the 0th page // parameter is optional, in case its not present, we default to the 0th page
Integer page = !parameters.isEmpty() ? (Integer) parameters.get(0) : 1; Integer page = !parameters.isEmpty() ? (Integer) parameters.get(0) : 1;
AServer server = serverManagementService.loadServer(commandContext.getGuild()); return getMessageToSend(commandContext.getAuthor(), page)
.thenCompose(messageToSend -> FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())))
.thenApply(aVoid -> CommandResult.fromIgnored());
}
private CompletableFuture<MessageToSend> getMessageToSend(Member actorUser, Integer page) {
AServer server = serverManagementService.loadServer(actorUser.getGuild());
LeaderBoard leaderBoard = userExperienceService.findLeaderBoardData(server, page); LeaderBoard leaderBoard = userExperienceService.findLeaderBoardData(server, page);
LeaderBoardModel leaderBoardModel = (LeaderBoardModel) ContextConverter.slimFromCommandContext(commandContext, LeaderBoardModel.class);
List<CompletableFuture> futures = new ArrayList<>(); List<CompletableFuture> futures = new ArrayList<>();
CompletableFuture<List<LeaderBoardEntryModel>> completableFutures = converter.fromLeaderBoard(leaderBoard); CompletableFuture<List<LeaderBoardEntryModel>> completableFutures = converter.fromLeaderBoard(leaderBoard);
futures.add(completableFutures); futures.add(completableFutures);
log.info("Rendering leaderboard for page {} in server {} for user {}.", page, commandContext.getAuthor().getId(), commandContext.getGuild().getId()); log.info("Rendering leaderboard for page {} in server {} for user {}.", page, actorUser.getId(), actorUser.getGuild().getId());
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor()); AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(actorUser);
LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(aUserInAServer); LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(aUserInAServer);
CompletableFuture<List<LeaderBoardEntryModel>> userRankFuture = converter.fromLeaderBoardEntry(Arrays.asList(userRank)); CompletableFuture<List<LeaderBoardEntryModel>> userRankFuture = converter.fromLeaderBoardEntry(Arrays.asList(userRank));
futures.add(userRankFuture); futures.add(userRankFuture);
return FutureUtils.toSingleFuture(futures).thenCompose(aVoid -> { return FutureUtils.toSingleFuture(futures).thenCompose(aVoid -> {
List<LeaderBoardEntryModel> finalModels = completableFutures.join(); List<LeaderBoardEntryModel> finalModels = completableFutures.join();
leaderBoardModel.setUserExperiences(finalModels); LeaderBoardModel leaderBoardModel = LeaderBoardModel
leaderBoardModel.setUserExecuting(userRankFuture.join().get(0)); .builder()
MessageToSend messageToSend = templateService.renderEmbedTemplate(LEADER_BOARD_POST_EMBED_TEMPLATE, leaderBoardModel, commandContext.getGuild().getIdLong()); .userExperiences(finalModels)
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())); .userExecuting(userRankFuture.join().get(0))
}).thenApply(aVoid -> CommandResult.fromIgnored()); .build();
return CompletableFuture.completedFuture(templateService.renderEmbedTemplate(LEADER_BOARD_POST_EMBED_TEMPLATE, leaderBoardModel, actorUser.getGuild().getIdLong()));
});
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Integer page;
if(slashCommandParameterService.hasCommandOption(PAGE_PARAMETER, event)) {
page = slashCommandParameterService.getCommandOption(PAGE_PARAMETER, event, Integer.class);
} else {
page = 1;
}
return getMessageToSend(event.getMember(), page)
.thenCompose(messageToSend -> interactionService.replyMessageToSend(messageToSend, event))
.thenApply(aVoid -> CommandResult.fromIgnored());
} }
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
List<ParameterValidator> leaderBoardPageValidators = Arrays.asList(MinIntegerValueValidator.min(0L)); List<ParameterValidator> leaderBoardPageValidators = Arrays.asList(MinIntegerValueValidator.min(0L));
parameters.add(Parameter.builder().name("page").validators(leaderBoardPageValidators).optional(true).templated(true).type(Integer.class).build()); Parameter pageParameter = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(PAGE_PARAMETER)
.validators(leaderBoardPageValidators)
.optional(true)
.templated(true)
.type(Integer.class)
.build();
List<Parameter> parameters = Arrays.asList(pageParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE)
.commandName(LEADERBOARD_PARAMTER)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("leaderboard") .name(LEADERBOARD_PARAMTER)
.module(ExperienceModuleDefinition.EXPERIENCE) .module(ExperienceModuleDefinition.EXPERIENCE)
.templated(true) .templated(true)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)
.parameters(parameters) .parameters(parameters)

View File

@@ -4,17 +4,23 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService; 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.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition; import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
import dev.sheldan.abstracto.experience.model.template.LevelRole; import dev.sheldan.abstracto.experience.model.template.LevelRole;
import dev.sheldan.abstracto.experience.model.template.LevelRolesModel; import dev.sheldan.abstracto.experience.model.template.LevelRolesModel;
import dev.sheldan.abstracto.experience.service.ExperienceRoleService; import dev.sheldan.abstracto.experience.service.ExperienceRoleService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -27,6 +33,9 @@ import java.util.stream.Collectors;
@Component @Component
public class LevelRoles extends AbstractConditionableCommand { public class LevelRoles extends AbstractConditionableCommand {
private static final String LEVEL_ROLES_COMMAND = "levelRoles";
private static final String LEVEL_ROLES_TEMPLATE_KEY = "levelRoles_response";
@Autowired @Autowired
private ExperienceRoleService experienceRoleService; private ExperienceRoleService experienceRoleService;
@@ -36,29 +45,58 @@ public class LevelRoles extends AbstractConditionableCommand {
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
private static final String LEVEL_ROLES_TEMPLATE_KEY = "levelRoles_response"; @Autowired
private TemplateService templateService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
AServer server = serverManagementService.loadServer(commandContext.getGuild()); MessageToSend messageToSend = getResponseModel(commandContext.getGuild().getIdLong());
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromSuccess());
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Long serverId = event.getGuild().getIdLong();
MessageToSend messageToSend = getResponseModel(serverId);
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
private MessageToSend getResponseModel(Long serverId) {
AServer server = serverManagementService.loadServer(serverId);
List<LevelRole> levelRoles = experienceRoleService.loadLevelRoleConfigForServer(server); List<LevelRole> levelRoles = experienceRoleService.loadLevelRoleConfigForServer(server);
levelRoles = levelRoles.stream().sorted(Comparator.comparingInt(LevelRole::getLevel).reversed()).collect(Collectors.toList()); levelRoles = levelRoles.stream().sorted(Comparator.comparingInt(LevelRole::getLevel).reversed()).collect(Collectors.toList());
LevelRolesModel model = LevelRolesModel LevelRolesModel model = LevelRolesModel
.builder() .builder()
.levelRoles(levelRoles) .levelRoles(levelRoles)
.build(); .build();
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(LEVEL_ROLES_TEMPLATE_KEY, model, commandContext.getChannel())) return templateService.renderEmbedTemplate(LEVEL_ROLES_TEMPLATE_KEY, model, serverId);
.thenApply(unused -> CommandResult.fromSuccess());
} }
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE)
.commandName(LEVEL_ROLES_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("levelRoles") .name(LEVEL_ROLES_COMMAND)
.module(ExperienceModuleDefinition.EXPERIENCE) .module(ExperienceModuleDefinition.EXPERIENCE)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.parameters(parameters) .parameters(parameters)

View File

@@ -4,22 +4,28 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.FullRole; import dev.sheldan.abstracto.core.models.FullRole;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.RoleService; import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService; 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.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition; import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
import dev.sheldan.abstracto.experience.model.database.ADisabledExpRole; import dev.sheldan.abstracto.experience.model.database.ADisabledExpRole;
import dev.sheldan.abstracto.experience.model.template.DisabledExperienceRolesModel; import dev.sheldan.abstracto.experience.model.template.DisabledExperienceRolesModel;
import dev.sheldan.abstracto.experience.service.management.DisabledExpRoleManagementService; import dev.sheldan.abstracto.experience.service.management.DisabledExpRoleManagementService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -34,6 +40,9 @@ import java.util.concurrent.CompletableFuture;
@Component @Component
public class ListDisabledExperienceRoles extends AbstractConditionableCommand { public class ListDisabledExperienceRoles extends AbstractConditionableCommand {
private static final String LIST_DISABLED_EXPERIENCE_ROLES_RESPONSE = "list_disabled_experience_roles";
private static final String LIST_DISABLED_EXPERIENCE_ROLES_COMMAND = "listDisabledExperienceRoles";
@Autowired @Autowired
private DisabledExpRoleManagementService disabledExpRoleManagementService; private DisabledExpRoleManagementService disabledExpRoleManagementService;
@@ -46,11 +55,35 @@ public class ListDisabledExperienceRoles extends AbstractConditionableCommand {
@Autowired @Autowired
private ServerManagementService serverManagementService; private ServerManagementService serverManagementService;
@Autowired
private TemplateService templateService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
AServer server = serverManagementService.loadServer(commandContext.getGuild()); Long serverId = commandContext.getGuild().getIdLong();
MessageToSend messageToSend = getResponseModel(serverId, commandContext.getAuthor());
List<CompletableFuture<Message>> futures = channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel());
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored());
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Long serverId = event.getGuild().getIdLong();
MessageToSend messageToSend = getResponseModel(serverId, event.getMember());
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
private MessageToSend getResponseModel(Long serverId, Member member) {
AServer server = serverManagementService.loadServer(serverId);
List<ADisabledExpRole> disabledRolesForServer = disabledExpRoleManagementService.getDisabledRolesForServer(server); List<ADisabledExpRole> disabledRolesForServer = disabledExpRoleManagementService.getDisabledRolesForServer(server);
DisabledExperienceRolesModel disabledExperienceRolesModel = (DisabledExperienceRolesModel) ContextConverter.fromCommandContext(commandContext, DisabledExperienceRolesModel.class); DisabledExperienceRolesModel disabledExperienceRolesModel = DisabledExperienceRolesModel
.builder()
.member(member)
.build();
disabledRolesForServer.forEach(aDisabledExpRole -> { disabledRolesForServer.forEach(aDisabledExpRole -> {
Role jdaRole = null; Role jdaRole = null;
if(!aDisabledExpRole.getRole().getDeleted()) { if(!aDisabledExpRole.getRole().getDeleted()) {
@@ -63,18 +96,29 @@ public class ListDisabledExperienceRoles extends AbstractConditionableCommand {
.build(); .build();
disabledExperienceRolesModel.getRoles().add(role); disabledExperienceRolesModel.getRoles().add(role);
}); });
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInTextChannelList("list_disabled_experience_roles", disabledExperienceRolesModel, commandContext.getChannel()); return templateService.renderEmbedTemplate(LIST_DISABLED_EXPERIENCE_ROLES_RESPONSE, disabledExperienceRolesModel, serverId);
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored());
} }
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
List<String> aliases = Arrays.asList("lsDisEpRoles"); List<String> aliases = Arrays.asList("lsDisEpRoles");
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE_CONFIG)
.commandName(LIST_DISABLED_EXPERIENCE_ROLES_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("listDisabledExperienceRoles") .name(LIST_DISABLED_EXPERIENCE_ROLES_COMMAND)
.module(ExperienceModuleDefinition.EXPERIENCE) .module(ExperienceModuleDefinition.EXPERIENCE)
.slashCommandConfig(slashCommandConfig)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)

View File

@@ -4,15 +4,19 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition; import dev.sheldan.abstracto.experience.config.ExperienceFeatureDefinition;
import dev.sheldan.abstracto.experience.config.ExperienceSlashCommandNames;
import dev.sheldan.abstracto.experience.converter.LeaderBoardModelConverter; import dev.sheldan.abstracto.experience.converter.LeaderBoardModelConverter;
import dev.sheldan.abstracto.experience.model.LeaderBoardEntry; import dev.sheldan.abstracto.experience.model.LeaderBoardEntry;
import dev.sheldan.abstracto.experience.model.database.AUserExperience; import dev.sheldan.abstracto.experience.model.database.AUserExperience;
@@ -25,11 +29,11 @@ import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -42,6 +46,8 @@ import java.util.concurrent.CompletableFuture;
public class Rank extends AbstractConditionableCommand { public class Rank extends AbstractConditionableCommand {
public static final String RANK_POST_EMBED_TEMPLATE = "rank_post"; public static final String RANK_POST_EMBED_TEMPLATE = "rank_post";
public static final String RANK_COMMAND = "rank";
public static final String MEMBER_PARAMETER = "member";
@Autowired @Autowired
private LeaderBoardModelConverter converter; private LeaderBoardModelConverter converter;
@@ -66,43 +72,89 @@ public class Rank extends AbstractConditionableCommand {
@Autowired @Autowired
private UserExperienceManagementService userExperienceManagementService; private UserExperienceManagementService userExperienceManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
Member parameter = !parameters.isEmpty() ? (Member) parameters.get(0) : commandContext.getAuthor(); Member targetMember = !parameters.isEmpty() ? (Member) parameters.get(0) : commandContext.getAuthor();
if(!parameter.getGuild().equals(commandContext.getGuild())) { if(!targetMember.getGuild().equals(commandContext.getGuild())) {
throw new EntityGuildMismatchException(); throw new EntityGuildMismatchException();
} }
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(parameter); AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(targetMember);
LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(aUserInAServer); LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(aUserInAServer);
CompletableFuture<List<LeaderBoardEntryModel>> future = converter.fromLeaderBoardEntry(Arrays.asList(userRank)); CompletableFuture<List<LeaderBoardEntryModel>> future = converter.fromLeaderBoardEntry(Arrays.asList(userRank));
RankModel rankModel = RankModel RankModel rankModel = RankModel
.builder() .builder()
.member(parameter) .member(targetMember)
.build(); .build();
return future.thenCompose(leaderBoardEntryModel -> return future.thenCompose(leaderBoardEntryModel -> {
self.renderAndSendRank(commandContext, parameter, rankModel, leaderBoardEntryModel.get(0)) MessageToSend messageToSend = self.renderMessageToSend(targetMember, rankModel, leaderBoardEntryModel.get(0));
).thenApply(result -> CommandResult.fromIgnored()); return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()));
}).thenApply(result -> CommandResult.fromIgnored());
} }
@Transactional @Transactional
public CompletableFuture<Void> renderAndSendRank(CommandContext commandContext, Member toRender, RankModel rankModel, LeaderBoardEntryModel leaderBoardEntryModel) { public MessageToSend renderMessageToSend(Member toRender, RankModel rankModel, LeaderBoardEntryModel leaderBoardEntryModel) {
rankModel.setRankUser(leaderBoardEntryModel); rankModel.setRankUser(leaderBoardEntryModel);
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(toRender); AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(toRender);
AUserExperience experienceObj = userExperienceManagementService.findUserInServer(aUserInAServer); AUserExperience experienceObj = userExperienceManagementService.findUserInServer(aUserInAServer);
log.info("Rendering rank for user {} in server {}.", toRender.getId(), commandContext.getGuild().getId()); log.info("Rendering rank for user {} in server {}.", toRender.getId(), toRender.getGuild().getId());
rankModel.setExperienceToNextLevel(experienceLevelService.calculateExperienceToNextLevel(experienceObj.getCurrentLevel().getLevel(), experienceObj.getExperience())); rankModel.setExperienceToNextLevel(experienceLevelService.calculateExperienceToNextLevel(experienceObj.getCurrentLevel().getLevel(), experienceObj.getExperience()));
MessageToSend messageToSend = templateService.renderEmbedTemplate(RANK_POST_EMBED_TEMPLATE, rankModel, commandContext.getGuild().getIdLong()); return templateService.renderEmbedTemplate(RANK_POST_EMBED_TEMPLATE, rankModel, toRender.getGuild().getIdLong());
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())); }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member targetMember;
if(slashCommandParameterService.hasCommandOption(MEMBER_PARAMETER, event)) {
targetMember = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER, event, Member.class);
} else {
targetMember = event.getMember();
}
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(targetMember);
LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(aUserInAServer);
CompletableFuture<List<LeaderBoardEntryModel>> future = converter.fromLeaderBoardEntry(Arrays.asList(userRank));
RankModel rankModel = RankModel
.builder()
.member(targetMember)
.build();
return future.thenCompose(leaderBoardEntryModel -> {
MessageToSend messageToSend = self.renderMessageToSend(targetMember, rankModel, leaderBoardEntryModel.get(0));
return interactionService.replyMessageToSend(messageToSend, event);
}).thenApply(result -> CommandResult.fromIgnored());
} }
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("member").templated(true).type(Member.class).optional(true).build()); Parameter memberParameter = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(MEMBER_PARAMETER)
.templated(true)
.type(Member.class)
.optional(true)
.build();
List<Parameter> parameters = Arrays.asList(memberParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ExperienceSlashCommandNames.EXPERIENCE)
.commandName(RANK_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("rank") .name(RANK_COMMAND)
.slashCommandConfig(slashCommandConfig)
.module(ExperienceModuleDefinition.EXPERIENCE) .module(ExperienceModuleDefinition.EXPERIENCE)
.templated(true) .templated(true)
.async(true) .async(true)

View File

@@ -1,64 +0,0 @@
package dev.sheldan.abstracto.experience.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.experience.service.management.DisabledExpRoleManagementService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
@Slf4j
public class DisableExpForRoleTest {
@InjectMocks
private DisableExpForRole testUnit;
@Mock
private RoleManagementService roleManagementService;
@Mock
private DisabledExpRoleManagementService disabledExpRoleManagementService;
@Test
public void testExecuteCommandForNotDisabledRole() {
executeDisableExpForRoleTest(false, 1);
}
@Test
public void testExecuteCommandForDisabledRole() {
executeDisableExpForRoleTest(true, 0);
}
private void executeDisableExpForRoleTest(boolean value, int wantedNumberOfInvocations) {
ARole parameterRole = Mockito.mock(ARole.class);
ARole actualRole = Mockito.mock(ARole.class);
when(parameterRole.getId()).thenReturn(5L);
CommandContext context = CommandTestUtilities.getWithParameters(Arrays.asList(parameterRole));
AServer server = Mockito.mock(AServer.class);
when(actualRole.getServer()).thenReturn(server);
when(roleManagementService.findRole(parameterRole.getId())).thenReturn(actualRole);
when(disabledExpRoleManagementService.isExperienceDisabledForRole(actualRole)).thenReturn(value);
CommandResult result = testUnit.execute(context);
verify(disabledExpRoleManagementService, times(wantedNumberOfInvocations)).setRoleToBeDisabledForExp(actualRole);
CommandTestUtilities.checkSuccessfulCompletion(result);
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,93 +0,0 @@
package dev.sheldan.abstracto.experience.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.experience.converter.LeaderBoardModelConverter;
import dev.sheldan.abstracto.experience.model.LeaderBoard;
import dev.sheldan.abstracto.experience.model.LeaderBoardEntry;
import dev.sheldan.abstracto.experience.model.template.LeaderBoardEntryModel;
import dev.sheldan.abstracto.experience.model.template.LeaderBoardModel;
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class LeaderBoardCommandTest {
@InjectMocks
private LeaderBoardCommand testUnit;
@Mock
private AUserExperienceService userExperienceService;
@Mock
private TemplateService templateService;
@Mock
private ChannelService channelService;
@Mock
private LeaderBoardModelConverter converter;
@Mock
private UserInServerManagementService userInServerManagementService;
@Mock
private ServerManagementService serverManagementService;
private static final Long SERVER_ID = 45L;
@Test
public void testLeaderBoardWithNoParameter() {
testLeaderBoardCommand(CommandTestUtilities.getNoParameters(), 1);
}
@Test
public void testLeaderBoardWithPageParameter() {
testLeaderBoardCommand(CommandTestUtilities.getWithParameters(Arrays.asList(5)), 5);
}
private void testLeaderBoardCommand(CommandContext context, int expectedPage) {
when(context.getGuild().getIdLong()).thenReturn(SERVER_ID);
LeaderBoard leaderBoard = Mockito.mock(LeaderBoard.class);
AServer server = Mockito.mock(AServer.class);
when(serverManagementService.loadServer(context.getGuild())).thenReturn(server);
AUserInAServer userInAServer = Mockito.mock(AUserInAServer.class);
when(userInServerManagementService.loadOrCreateUser(context.getAuthor())).thenReturn(userInAServer);
when(userExperienceService.findLeaderBoardData(server, expectedPage)).thenReturn(leaderBoard);
when(converter.fromLeaderBoard(leaderBoard)).thenReturn(CompletableFuture.completedFuture(null));
LeaderBoardEntry executingUserRank = Mockito.mock(LeaderBoardEntry.class);
when(userExperienceService.getRankOfUserInServer(userInAServer)).thenReturn(executingUserRank);
LeaderBoardEntryModel leaderBoardEntryModel = Mockito.mock(LeaderBoardEntryModel.class);
when(converter.fromLeaderBoardEntry(Arrays.asList(executingUserRank))).thenReturn(CompletableFuture.completedFuture(Arrays.asList(leaderBoardEntryModel)));
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(eq(LeaderBoardCommand.LEADER_BOARD_POST_EMBED_TEMPLATE), any(LeaderBoardModel.class), eq(SERVER_ID))).thenReturn(messageToSend);
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);
verify(channelService, times(1)).sendMessageToSendToChannel(messageToSend, context.getChannel());
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,90 +0,0 @@
package dev.sheldan.abstracto.experience.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.experience.model.database.ADisabledExpRole;
import dev.sheldan.abstracto.experience.model.template.DisabledExperienceRolesModel;
import dev.sheldan.abstracto.experience.service.management.DisabledExpRoleManagementService;
import net.dv8tion.jda.api.entities.Role;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class ListDisabledExperienceRolesTest {
@InjectMocks
private ListDisabledExperienceRoles testUnit;
@Mock
private DisabledExpRoleManagementService disabledExpRoleManagementService;
@Mock
private RoleService roleService;
@Mock
private ChannelService channelService;
@Mock
private ServerManagementService serverManagementService;
@Mock
private AServer server;
@Test
public void testCommandExecutionNoRolesFound() {
CommandContext context = CommandTestUtilities.getNoParameters();
when(serverManagementService.loadServer(context.getGuild())).thenReturn(server);
when(disabledExpRoleManagementService.getDisabledRolesForServer(server)).thenReturn(new ArrayList<>());
when(channelService.sendEmbedTemplateInTextChannelList(eq("list_disabled_experience_roles"),
any(DisabledExperienceRolesModel.class), eq(context.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
verify(roleService, times(0)).getRoleFromGuild(any(ARole.class));
}
@Test
public void testCommandExecutionRolesFound() {
CommandContext context = CommandTestUtilities.getNoParameters();
ADisabledExpRole disabledExpRole1 = Mockito.mock(ADisabledExpRole.class);
ADisabledExpRole disabledExpRole2 = Mockito.mock(ADisabledExpRole.class);
when(disabledExpRoleManagementService.getDisabledRolesForServer(server)).thenReturn(Arrays.asList(disabledExpRole1, disabledExpRole2));
Role role1 = Mockito.mock(Role.class);
Role role2 = Mockito.mock(Role.class);
ARole aRole = Mockito.mock(ARole.class);
ARole aRole2 = Mockito.mock(ARole.class);
when(roleService.getRoleFromGuild(aRole)).thenReturn(role1);
when(roleService.getRoleFromGuild(aRole2)).thenReturn(role2);
when(aRole.getDeleted()).thenReturn(false);
when(aRole2.getDeleted()).thenReturn(false);
when(disabledExpRole1.getRole()).thenReturn(aRole);
when(disabledExpRole2.getRole()).thenReturn(aRole2);
when(serverManagementService.loadServer(context.getGuild())).thenReturn(server);
when(channelService.sendEmbedTemplateInTextChannelList(eq("list_disabled_experience_roles"),
any(DisabledExperienceRolesModel.class), eq(context.getChannel()))).thenReturn(CommandTestUtilities.messageFutureList());
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,110 +0,0 @@
package dev.sheldan.abstracto.experience.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.experience.converter.LeaderBoardModelConverter;
import dev.sheldan.abstracto.experience.model.LeaderBoardEntry;
import dev.sheldan.abstracto.experience.model.database.AExperienceLevel;
import dev.sheldan.abstracto.experience.model.database.AUserExperience;
import dev.sheldan.abstracto.experience.model.template.LeaderBoardEntryModel;
import dev.sheldan.abstracto.experience.model.template.RankModel;
import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import dev.sheldan.abstracto.experience.service.ExperienceLevelService;
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import net.dv8tion.jda.api.entities.Member;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static dev.sheldan.abstracto.experience.command.Rank.RANK_POST_EMBED_TEMPLATE;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class RankTest {
@InjectMocks
private Rank testUnit;
@Mock
private LeaderBoardModelConverter converter;
@Mock
private TemplateService templateService;
@Mock
private AUserExperienceService userExperienceService;
@Mock
private ExperienceLevelService experienceLevelService;
@Mock
private ChannelService channelService;
@Mock
private UserInServerManagementService userInServerManagementService;
@Mock
private Rank self;
private static final Long SERVER_ID = 4L;
@Mock
private AUserInAServer aUserInAServer;
@Mock
private UserExperienceManagementService userExperienceManagementService;
@Test
public void testRankExecution() {
CommandContext context = CommandTestUtilities.getNoParameters();
LeaderBoardEntry leaderBoardEntry = Mockito.mock(LeaderBoardEntry.class);
when(userInServerManagementService.loadOrCreateUser(context.getAuthor())).thenReturn(aUserInAServer);
when(userExperienceService.getRankOfUserInServer(aUserInAServer)).thenReturn(leaderBoardEntry);
LeaderBoardEntryModel leaderBoardEntryModel = Mockito.mock(LeaderBoardEntryModel.class);
when(context.getAuthor().getGuild()).thenReturn(context.getGuild());
when(converter.fromLeaderBoardEntry(Arrays.asList(leaderBoardEntry))).thenReturn(CompletableFuture.completedFuture(Arrays.asList(leaderBoardEntryModel)));
when(self.renderAndSendRank(eq(context), any(Member.class), any(RankModel.class), eq(leaderBoardEntryModel))).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
}
@Test
public void testRenderAndSend() {
int currentLevelValue = 50;
long currentExperience = 50L;
AExperienceLevel currentLevel = Mockito.mock(AExperienceLevel.class);
when(currentLevel.getLevel()).thenReturn(currentLevelValue);
AUserExperience aUserExperience = Mockito.mock(AUserExperience.class);
when(aUserExperience.getCurrentLevel()).thenReturn(currentLevel);
when(aUserExperience.getExperience()).thenReturn(currentExperience);
CommandContext context = CommandTestUtilities.getNoParameters();
when(context.getGuild().getIdLong()).thenReturn(SERVER_ID);
RankModel rankModel = Mockito.mock(RankModel.class);
LeaderBoardEntryModel leaderBoardEntryModel = Mockito.mock(LeaderBoardEntryModel.class);
when(userInServerManagementService.loadOrCreateUser(context.getAuthor())).thenReturn(aUserInAServer);
when(userExperienceManagementService.findUserInServer(aUserInAServer)).thenReturn(aUserExperience);
when(experienceLevelService.calculateExperienceToNextLevel(currentLevelValue, currentExperience)).thenReturn(140L);
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(RANK_POST_EMBED_TEMPLATE, rankModel, SERVER_ID)).thenReturn(messageToSend);
when(channelService.sendMessageToSendToChannel(messageToSend, context.getChannel())).thenReturn(Arrays.asList(CompletableFuture.completedFuture(null)));
testUnit.renderAndSendRank(context, context.getAuthor(), rankModel, leaderBoardEntryModel).join();
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.experience.config;
public class ExperienceSlashCommandNames {
public static final String EXPERIENCE = "experience";
public static final String EXPERIENCE_CONFIG = "experienceconfig";
}

View File

@@ -1,10 +1,9 @@
package dev.sheldan.abstracto.experience.model.template; package dev.sheldan.abstracto.experience.model.template;
import dev.sheldan.abstracto.core.models.FullRole; import dev.sheldan.abstracto.core.models.FullRole;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.experimental.SuperBuilder; import net.dv8tion.jda.api.entities.Member;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -13,11 +12,12 @@ import java.util.List;
* Model used to render an overview of the roles for which experience gain has been disabled on the current server. * Model used to render an overview of the roles for which experience gain has been disabled on the current server.
*/ */
@Getter @Getter
@SuperBuilder @Builder
public class DisabledExperienceRolesModel extends UserInitiatedServerContext { public class DisabledExperienceRolesModel {
/** /**
* A list of {@link FullRole roles} for which experience gain is disabled in this server * A list of {@link FullRole roles} for which experience gain is disabled in this server
*/ */
@Builder.Default @Builder.Default
private List<FullRole> roles = new ArrayList<>(); private List<FullRole> roles = new ArrayList<>();
private Member member;
} }

View File

@@ -50,9 +50,6 @@ public class MessageEmbedListenerTest {
@Mock @Mock
private MessageEmbedListener self; private MessageEmbedListener self;
@Mock
private GuildMemberMessageChannel context;
@Mock @Mock
private Message message; private Message message;
@@ -65,6 +62,9 @@ public class MessageEmbedListenerTest {
@Mock @Mock
private Guild guild; private Guild guild;
@Mock
private Member member;
private static final Long FIRST_SERVER_ID = 12L; private static final Long FIRST_SERVER_ID = 12L;
private static final Long SECOND_SERVER_ID = 13L; private static final Long SECOND_SERVER_ID = 13L;
private static final Long FIRST_CHANNEL_ID = 45L; private static final Long FIRST_CHANNEL_ID = 45L;
@@ -75,8 +75,10 @@ public class MessageEmbedListenerTest {
@Before @Before
public void setup(){ public void setup(){
when(guild.getIdLong()).thenReturn(FIRST_SERVER_ID); when(guild.getIdLong()).thenReturn(FIRST_SERVER_ID);
when(context.getGuild()).thenReturn(guild); when(model.getMessage()).thenReturn(message);
when(context.getGuildChannel()).thenReturn(textChannel); when(message.getGuild()).thenReturn(guild);
when(message.getChannel()).thenReturn(textChannel);
when(message.getMember()).thenReturn(member);
} }
@Test @Test
@@ -126,9 +128,7 @@ public class MessageEmbedListenerTest {
when(foundLink.getMessageId()).thenReturn(FIRST_MESSAGE_ID); when(foundLink.getMessageId()).thenReturn(FIRST_MESSAGE_ID);
when(foundLink.getServerId()).thenReturn(SECOND_SERVER_ID); when(foundLink.getServerId()).thenReturn(SECOND_SERVER_ID);
List<MessageEmbedLink> foundMessageLinks = Arrays.asList(foundLink); List<MessageEmbedLink> foundMessageLinks = Arrays.asList(foundLink);
Member author = Mockito.mock(Member.class); when(userInServerManagementService.loadOrCreateUser(member)).thenReturn(userInAServer);
when(context.getMember()).thenReturn(author);
when(userInServerManagementService.loadOrCreateUser(author)).thenReturn(userInAServer);
when(messageEmbedService.getLinksInMessage(text)).thenReturn(foundMessageLinks); when(messageEmbedService.getLinksInMessage(text)).thenReturn(foundMessageLinks);
when(model.getMessage()).thenReturn(message); when(model.getMessage()).thenReturn(message);
testUnit.execute(model); testUnit.execute(model);
@@ -155,11 +155,8 @@ public class MessageEmbedListenerTest {
String completeMessage = firstText.concat(secondText); String completeMessage = firstText.concat(secondText);
when(message.getContentRaw()).thenReturn(completeMessage); when(message.getContentRaw()).thenReturn(completeMessage);
setupMessageConfig(); setupMessageConfig();
Member author = Mockito.mock(Member.class);
when(context.getMember()).thenReturn(author);
when(context.getGuild()).thenReturn(guild);
when(guild.getIdLong()).thenReturn(FIRST_SERVER_ID); when(guild.getIdLong()).thenReturn(FIRST_SERVER_ID);
when(userInServerManagementService.loadOrCreateUser(author)).thenReturn(embeddingUser); when(userInServerManagementService.loadOrCreateUser(member)).thenReturn(embeddingUser);
CachedMessage cachedMessage = Mockito.mock(CachedMessage.class); CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
when(messageCache.getMessageFromCache(FIRST_SERVER_ID, FIRST_CHANNEL_ID, FIRST_MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(cachedMessage)); when(messageCache.getMessageFromCache(FIRST_SERVER_ID, FIRST_CHANNEL_ID, FIRST_MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(cachedMessage));
when(messageEmbedService.getLinksInMessage(completeMessage)).thenReturn(foundMessageLinks); when(messageEmbedService.getLinksInMessage(completeMessage)).thenReturn(foundMessageLinks);
@@ -187,9 +184,7 @@ public class MessageEmbedListenerTest {
when(userInAServer.getUserInServerId()).thenReturn(USER_IN_SERVER_ID); when(userInAServer.getUserInServerId()).thenReturn(USER_IN_SERVER_ID);
when(message.getContentRaw()).thenReturn(text); when(message.getContentRaw()).thenReturn(text);
setupMessageConfig(); setupMessageConfig();
Member author = Mockito.mock(Member.class); when(userInServerManagementService.loadOrCreateUser(member)).thenReturn(userInAServer);
when(context.getMember()).thenReturn(author);
when(userInServerManagementService.loadOrCreateUser(author)).thenReturn(userInAServer);
CachedMessage cachedMessage = Mockito.mock(CachedMessage.class); CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
CachedMessage secondCachedMessage = Mockito.mock(CachedMessage.class); CachedMessage secondCachedMessage = Mockito.mock(CachedMessage.class);
when(messageCache.getMessageFromCache(FIRST_SERVER_ID, FIRST_CHANNEL_ID, FIRST_MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(cachedMessage)); when(messageCache.getMessageFromCache(FIRST_SERVER_ID, FIRST_CHANNEL_ID, FIRST_MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(cachedMessage));
@@ -206,8 +201,8 @@ public class MessageEmbedListenerTest {
public void testLoadUserAndEmbed() { public void testLoadUserAndEmbed() {
CachedMessage cachedMessage = Mockito.mock(CachedMessage.class); CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
long userId = 3L; long userId = 3L;
when(context.getGuildChannel()).thenReturn(textChannel); when(message.getGuildChannel()).thenReturn(textChannel);
when(messageEmbedService.embedLink(cachedMessage, textChannel, userId, context)).thenReturn(CompletableFuture.completedFuture(null)); when(messageEmbedService.embedLink(eq(cachedMessage), eq(textChannel), eq(userId), any(GuildMemberMessageChannel.class))).thenReturn(CompletableFuture.completedFuture(null));
testUnit.embedSingleLink(message, userId, cachedMessage); testUnit.embedSingleLink(message, userId, cachedMessage);
verify(metricService, times(1)).incrementCounter(any()); verify(metricService, times(1)).incrementCounter(any());
} }
@@ -222,9 +217,7 @@ public class MessageEmbedListenerTest {
when(foundLink.getServerId()).thenReturn(FIRST_SERVER_ID); when(foundLink.getServerId()).thenReturn(FIRST_SERVER_ID);
when(foundLink.getChannelId()).thenReturn(FIRST_CHANNEL_ID); when(foundLink.getChannelId()).thenReturn(FIRST_CHANNEL_ID);
List<MessageEmbedLink> foundMessageLinks = Arrays.asList(foundLink); List<MessageEmbedLink> foundMessageLinks = Arrays.asList(foundLink);
Member author = Mockito.mock(Member.class); when(userInServerManagementService.loadOrCreateUser(member)).thenReturn(userInAServer);
when(context.getMember()).thenReturn(author);
when(userInServerManagementService.loadOrCreateUser(author)).thenReturn(userInAServer);
CachedMessage cachedMessage = Mockito.mock(CachedMessage.class); CachedMessage cachedMessage = Mockito.mock(CachedMessage.class);
when(messageCache.getMessageFromCache(FIRST_SERVER_ID, FIRST_CHANNEL_ID, FIRST_MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(cachedMessage)); when(messageCache.getMessageFromCache(FIRST_SERVER_ID, FIRST_CHANNEL_ID, FIRST_MESSAGE_ID)).thenReturn(CompletableFuture.completedFuture(cachedMessage));
when(messageEmbedService.getLinksInMessage(text)).thenReturn(foundMessageLinks); when(messageEmbedService.getLinksInMessage(text)).thenReturn(foundMessageLinks);

View File

@@ -2,23 +2,29 @@ package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.condition.CommandCondition; import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.config.EffectConfig;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.BanService; import dev.sheldan.abstracto.moderation.service.BanService;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.commands.OptionType;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -29,34 +35,107 @@ import static dev.sheldan.abstracto.moderation.service.BanService.BAN_EFFECT_KEY
@Slf4j @Slf4j
public class Ban extends AbstractConditionableCommand { public class Ban extends AbstractConditionableCommand {
public static final String BAN_DEFAULT_REASON_TEMPLATE = "ban_default_reason"; private static final String BAN_COMMAND = "ban";
private static final String REASON_PARAMETER = "reason";
private static final String USER_PARAMETER = "user";
public static final String BAN_NOTIFICATION_NOT_POSSIBLE = "ban_notification_not_possible";
private static final String BAN_RESPONSE = "ban_response";
@Autowired @Autowired
private BanService banService; private BanService banService;
@Autowired
private ChannelService channelService;
@Autowired @Autowired
private TemplateService templateService; private TemplateService templateService;
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private UserService userService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
User user = (User) parameters.get(0); User user = (User) parameters.get(0);
String reason = (String) parameters.get(1); String reason = (String) parameters.get(1);
Guild guild = commandContext.getGuild();
return banService.banUserWithNotification(user, reason, commandContext.getAuthor(), 0, commandContext.getMessage()) Message message = commandContext.getMessage();
Member banningMember = commandContext.getAuthor();
return banService.banUserWithNotification(user, reason, commandContext.getAuthor(), 0)
.thenCompose(banResult -> {
String errorNotification = templateService.renderSimpleTemplate(BAN_NOTIFICATION_NOT_POSSIBLE, guild.getIdLong());
return channelService.sendTextToChannel(errorNotification, message.getChannel())
.thenAccept(message1 -> log.info("Notified about not being able to send ban notification in server {} and channel {} from user {}."
, guild, message.getChannel().getIdLong(), banningMember.getIdLong()));
})
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String reason = slashCommandParameterService.getCommandOption(REASON_PARAMETER, event, String.class, String.class);
if(slashCommandParameterService.hasCommandOptionWithFullType(USER_PARAMETER, event, OptionType.USER)) {
Member member = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, User.class, Member.class);
return banService.banUserWithNotification(member.getUser(), reason, event.getMember(), 0)
.thenCompose(banResult -> interactionService.replyEmbed(BAN_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
} else {
String userIdStr = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, User.class, String.class);
Long userId = Long.parseLong(userIdStr);
return userService.retrieveUserForId(userId)
.thenCompose(user -> banService.banUserWithNotification(user, reason, event.getMember(), 0))
.thenCompose(banResult -> interactionService.replyEmbed(BAN_RESPONSE, event))
.thenApply(banResult -> CommandResult.fromSuccess());
}
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter userParameter = Parameter
parameters.add(Parameter.builder().name("user").templated(true).type(User.class).build()); .builder()
parameters.add(Parameter.builder().name("reason").templated(true).type(String.class).remainder(true).build()); .name(USER_PARAMETER)
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build(); .templated(true)
List<EffectConfig> effectConfig = Arrays.asList(EffectConfig.builder().position(0).effectKey(BAN_EFFECT_KEY).build()); .type(User.class)
.build();
Parameter reasonParameter = Parameter
.builder()
.name(REASON_PARAMETER)
.templated(true)
.type(String.class)
.remainder(true)
.build();
List<Parameter> parameters = Arrays.asList(userParameter, reasonParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.hasExample(true)
.build();
EffectConfig banEffect = EffectConfig
.builder()
.position(0)
.parameterName(USER_PARAMETER)
.effectKey(BAN_EFFECT_KEY)
.build();
List<EffectConfig> effectConfig = Arrays.asList(banEffect);
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.MODERATION)
.commandName(BAN_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("ban") .name(BAN_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true) .async(true)
.effects(effectConfig) .effects(effectConfig)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -9,10 +9,15 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.BanService; import dev.sheldan.abstracto.moderation.service.BanService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.entities.User;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -22,6 +27,7 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import static dev.sheldan.abstracto.moderation.command.Ban.BAN_NOTIFICATION_NOT_POSSIBLE;
import static dev.sheldan.abstracto.moderation.service.BanService.BAN_EFFECT_KEY; import static dev.sheldan.abstracto.moderation.service.BanService.BAN_EFFECT_KEY;
@Component @Component
@@ -31,13 +37,28 @@ public class BanDelete extends AbstractConditionableCommand {
@Autowired @Autowired
private BanService banService; private BanService banService;
@Autowired
private TemplateService templateService;
@Autowired
private ChannelService channelService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
User user = (User) parameters.get(0); User user = (User) parameters.get(0);
Integer delDays = (Integer) parameters.get(1); Integer delDays = (Integer) parameters.get(1);
String reason = (String) parameters.get(2); String reason = (String) parameters.get(2);
return banService.banUserWithNotification(user, reason, commandContext.getAuthor(), delDays, commandContext.getMessage()) Guild guild = commandContext.getGuild();
Message message = commandContext.getMessage();
Member banningMember = commandContext.getAuthor();
return banService.banUserWithNotification(user, reason, commandContext.getAuthor(), delDays)
.thenCompose(banResult -> {
String errorNotification = templateService.renderSimpleTemplate(BAN_NOTIFICATION_NOT_POSSIBLE, guild.getIdLong());
return channelService.sendTextToChannel(errorNotification, message.getChannel())
.thenAccept(message1 -> log.info("Notified about not being able to send ban notification in server {} and channel {} from user {}."
, guild, message.getChannel().getIdLong(), banningMember.getIdLong()));
})
.thenApply(unused -> CommandResult.fromSuccess()); .thenApply(unused -> CommandResult.fromSuccess());
} }

View File

@@ -4,14 +4,18 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService; import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.WarnService; import dev.sheldan.abstracto.moderation.service.WarnService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -22,12 +26,18 @@ import java.util.concurrent.CompletableFuture;
@Component @Component
public class DecayAllWarnings extends AbstractConditionableCommand { public class DecayAllWarnings extends AbstractConditionableCommand {
private static final String DECAY_ALL_WARNINGS_COMMAND = "decayAllWarnings";
private static final String DECAY_ALL_WARNINGS_RESPONSE = "decayAllWarnings_response";
@Autowired @Autowired
private WarnService warnService; private WarnService warnService;
@Autowired @Autowired
private ServerManagementService serverManagementService; private ServerManagementService serverManagementService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
AServer server = serverManagementService.loadServer(commandContext.getGuild()); AServer server = serverManagementService.loadServer(commandContext.getGuild());
@@ -35,15 +45,35 @@ public class DecayAllWarnings extends AbstractConditionableCommand {
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
AServer server = serverManagementService.loadServer(event.getGuild());
return warnService.decayAllWarningsForServer(server)
.thenCompose(unused -> interactionService.replyEmbed(DECAY_ALL_WARNINGS_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.MUTE)
.commandName(DECAY_ALL_WARNINGS_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("decayAllWarnings") .name(DECAY_ALL_WARNINGS_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.requiresConfirmation(true) .requiresConfirmation(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)

View File

@@ -4,14 +4,18 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService; import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.WarnService; import dev.sheldan.abstracto.moderation.service.WarnService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -22,12 +26,18 @@ import java.util.concurrent.CompletableFuture;
@Component @Component
public class DecayWarnings extends AbstractConditionableCommand { public class DecayWarnings extends AbstractConditionableCommand {
private static final String DECAY_WARNINGS_COMMAND = "decayWarnings";
private static final String DECAY_WARNINGS_RESPONSE = "decayWarnings_response";
@Autowired @Autowired
private WarnService warnService; private WarnService warnService;
@Autowired @Autowired
private ServerManagementService serverManagementService; private ServerManagementService serverManagementService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
AServer server = serverManagementService.loadServer(commandContext.getGuild()); AServer server = serverManagementService.loadServer(commandContext.getGuild());
@@ -35,14 +45,34 @@ public class DecayWarnings extends AbstractConditionableCommand {
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
AServer server = serverManagementService.loadServer(event.getGuild());
return warnService.decayWarningsForServer(server)
.thenCompose(unused -> interactionService.replyEmbed(DECAY_WARNINGS_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.WARN_DECAY)
.commandName(DECAY_WARNINGS_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("decayWarnings") .name(DECAY_WARNINGS_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.requiresConfirmation(true) .requiresConfirmation(true)
.async(true) .async(true)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -1,61 +1,87 @@
package dev.sheldan.abstracto.moderation.command; package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.ParameterValidator;
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator; import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.model.database.UserNote;
import dev.sheldan.abstracto.moderation.service.management.UserNoteManagementService; import dev.sheldan.abstracto.moderation.service.management.UserNoteManagementService;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component @Component
public class DeleteNote extends AbstractConditionableCommand { public class DeleteNote extends AbstractConditionableCommand {
public static final String NOTE_NOT_FOUND_EXCEPTION_TEMPLATE = "note_not_found_exception"; private static final String DELETE_NOTE_COMMAND = "deleteNote";
private static final String DELETE_NOTE_RESPONSE = "deleteNote_response";
private static final String ID_PARAMETER = "id";
@Autowired @Autowired
private UserNoteManagementService userNoteManagementService; private UserNoteManagementService userNoteManagementService;
@Autowired @Autowired
private TemplateService templateService; private SlashCommandParameterService slashCommandParameterService;
@Autowired @Autowired
private ServerManagementService serverManagementService; private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
Long id = (Long) commandContext.getParameters().getParameters().get(0); Long id = (Long) commandContext.getParameters().getParameters().get(0);
AServer server = serverManagementService.loadServer(commandContext.getGuild()); UserNote existingNote = userNoteManagementService.loadNote(commandContext.getGuild().getIdLong(), id);
if(userNoteManagementService.noteExists(id, server)) { userNoteManagementService.deleteNote(existingNote);
userNoteManagementService.deleteNote(id, server);
} else {
// TODO replace with exception
return CommandResult.fromError(templateService.renderSimpleTemplate(NOTE_NOT_FOUND_EXCEPTION_TEMPLATE, commandContext.getGuild().getIdLong()));
}
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Long userNoteId = slashCommandParameterService.getCommandOption(ID_PARAMETER, event, Integer.class).longValue();
UserNote existingNote = userNoteManagementService.loadNote(event.getGuild().getIdLong(), userNoteId);
userNoteManagementService.deleteNote(existingNote);
return interactionService.replyEmbed(DELETE_NOTE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
List<ParameterValidator> userNoteIdValidator = Arrays.asList(MinIntegerValueValidator.min(1L)); List<ParameterValidator> userNoteIdValidator = Arrays.asList(MinIntegerValueValidator.min(1L));
parameters.add(Parameter.builder().name("id").validators(userNoteIdValidator).type(Long.class).templated(true).build()); Parameter idParameter = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(ID_PARAMETER)
.validators(userNoteIdValidator)
.type(Long.class)
.templated(true)
.build();
parameters.add(idParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.USER_NOTES)
.commandName("delete")
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("deleteNote") .name(DELETE_NOTE_COMMAND)
.slashCommandConfig(slashCommandConfig)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -1,49 +1,87 @@
package dev.sheldan.abstracto.moderation.command; package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.ParameterValidator;
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator; import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.model.database.Warning; import dev.sheldan.abstracto.moderation.model.database.Warning;
import dev.sheldan.abstracto.moderation.service.management.WarnManagementService; import dev.sheldan.abstracto.moderation.service.management.WarnManagementService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.concurrent.CompletableFuture;
@Component @Component
public class DeleteWarning extends AbstractConditionableCommand { public class DeleteWarning extends AbstractConditionableCommand {
private static final String DELETE_WARNING_COMMAND = "deleteWarning";
private static final String DELETE_WARNING_RESPONSE = "deleteWarning_response";
private static final String WARN_ID_PARAMETER = "warnId";
@Autowired @Autowired
private WarnManagementService warnManagementService; private WarnManagementService warnManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
Long warnId = (Long) commandContext.getParameters().getParameters().get(0); Long warnId = (Long) commandContext.getParameters().getParameters().get(0);
Optional<Warning> optional = warnManagementService.findByIdOptional(warnId, commandContext.getGuild().getIdLong()); Warning warning = warnManagementService.findById(warnId, commandContext.getGuild().getIdLong());
optional.ifPresent(warning -> warnManagementService.deleteWarning(warning)); warnManagementService.deleteWarning(warning);
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Long warnId = slashCommandParameterService.getCommandOption(WARN_ID_PARAMETER, event, Long.class, Integer.class).longValue();
Warning warning = warnManagementService.findById(warnId, event.getGuild().getIdLong());
warnManagementService.deleteWarning(warning);
return interactionService.replyEmbed(DELETE_WARNING_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
List<ParameterValidator> warnIdValidator = Arrays.asList(MinIntegerValueValidator.min(1L)); List<ParameterValidator> warnIdValidator = Arrays.asList(MinIntegerValueValidator.min(1L));
parameters.add(Parameter.builder().name("warnId").validators(warnIdValidator).templated(true).type(Long.class).build()); Parameter warnIdParameter = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(WARN_ID_PARAMETER)
.validators(warnIdValidator)
.templated(true)
.type(Long.class)
.build();
List<Parameter> parameters = Arrays.asList(warnIdParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.WARNINGS)
.commandName("delete")
.build();
List<String> aliases = Arrays.asList("delWarn"); List<String> aliases = Arrays.asList("delWarn");
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("deleteWarning") .name(DELETE_WARNING_COMMAND)
.slashCommandConfig(slashCommandConfig)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -2,25 +2,24 @@ package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.condition.CommandCondition; import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.config.EffectConfig;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.model.template.command.KickLogModel; import dev.sheldan.abstracto.moderation.model.template.command.KickLogModel;
import dev.sheldan.abstracto.moderation.service.KickServiceBean; import dev.sheldan.abstracto.moderation.service.KickServiceBean;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -31,12 +30,22 @@ import static dev.sheldan.abstracto.moderation.service.KickService.KICK_EFFECT_K
public class Kick extends AbstractConditionableCommand { public class Kick extends AbstractConditionableCommand {
public static final String KICK_DEFAULT_REASON_TEMPLATE = "kick_default_reason"; public static final String KICK_DEFAULT_REASON_TEMPLATE = "kick_default_reason";
public static final String KICK_COMMAND = "kick";
public static final String USER_PARAMETER = "user";
public static final String REASON_PARAMETER = "reason";
private static final String KICK_RESPONSE = "kick_response";
@Autowired @Autowired
private TemplateService templateService; private TemplateService templateService;
@Autowired @Autowired
private KickServiceBean kickService; private KickServiceBean kickService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
@@ -47,24 +56,90 @@ public class Kick extends AbstractConditionableCommand {
String defaultReason = templateService.renderSimpleTemplate(KICK_DEFAULT_REASON_TEMPLATE, commandContext.getGuild().getIdLong()); String defaultReason = templateService.renderSimpleTemplate(KICK_DEFAULT_REASON_TEMPLATE, commandContext.getGuild().getIdLong());
String reason = parameters.size() == 2 ? (String) parameters.get(1) : defaultReason; String reason = parameters.size() == 2 ? (String) parameters.get(1) : defaultReason;
KickLogModel kickLogModel = (KickLogModel) ContextConverter.slimFromCommandContext(commandContext, KickLogModel.class); KickLogModel kickLogModel = KickLogModel
.builder()
.kickedUser(member)
.reason(reason)
.guild(commandContext.getGuild())
.channel(commandContext.getChannel())
.member(commandContext.getAuthor())
.build();
kickLogModel.setKickedUser(member); kickLogModel.setKickedUser(member);
kickLogModel.setReason(reason); kickLogModel.setReason(reason);
return kickService.kickMember(member, reason, kickLogModel) return kickService.kickMember(member, reason, kickLogModel)
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member member = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, Member.class);
if(!member.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
String reason;
if(slashCommandParameterService.hasCommandOption(REASON_PARAMETER, event)) {
reason = slashCommandParameterService.getCommandOption(REASON_PARAMETER, event, String.class);
} else {
reason = templateService.renderSimpleTemplate(KICK_DEFAULT_REASON_TEMPLATE, event.getGuild().getIdLong());
}
KickLogModel kickLogModel = KickLogModel
.builder()
.kickedUser(member)
.reason(reason)
.guild(event.getGuild())
.channel(event.getGuildChannel())
.member(event.getMember())
.build();
kickLogModel.setKickedUser(member);
kickLogModel.setReason(reason);
return kickService.kickMember(member, reason, kickLogModel)
.thenCompose(unused -> interactionService.replyEmbed(KICK_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter userParameter = Parameter
parameters.add(Parameter.builder().name("user").templated(true).type(Member.class).build()); .builder()
parameters.add(Parameter.builder().name("reason").templated(true).type(String.class).optional(true).remainder(true).build()); .name(USER_PARAMETER)
List<EffectConfig> effectConfig = Arrays.asList(EffectConfig.builder().position(0).effectKey(KICK_EFFECT_KEY).build()); .templated(true)
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build(); .type(Member.class)
.build();
Parameter reasonParameter = Parameter
.builder()
.name(REASON_PARAMETER)
.templated(true)
.type(String.class)
.optional(true)
.remainder(true)
.build();
List<Parameter> parameters = Arrays.asList(userParameter, reasonParameter);
EffectConfig kickEffect = EffectConfig
.builder()
.position(0)
.parameterName(USER_PARAMETER)
.effectKey(KICK_EFFECT_KEY)
.build();
List<EffectConfig> effectConfig = Arrays.asList(kickEffect);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.hasExample(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.MODERATION)
.commandName(KICK_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("kick") .name(KICK_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.async(true) .async(true)
.effects(effectConfig) .effects(effectConfig)

View File

@@ -2,27 +2,30 @@ package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.condition.CommandCondition; import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.config.EffectConfig;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.ServerChannelMessage; import dev.sheldan.abstracto.core.models.ServerChannelMessage;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.model.template.command.MuteContext; import dev.sheldan.abstracto.moderation.model.template.command.MuteContext;
import dev.sheldan.abstracto.moderation.service.MuteService; import dev.sheldan.abstracto.moderation.service.MuteService;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.GuildMessageChannel;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -32,7 +35,12 @@ import static dev.sheldan.abstracto.moderation.service.MuteService.MUTE_EFFECT_K
@Component @Component
public class Mute extends AbstractConditionableCommand { public class Mute extends AbstractConditionableCommand {
public static final String MUTE_DEFAULT_REASON_TEMPLATE = "mute_default_reason"; private static final String MUTE_DEFAULT_REASON_TEMPLATE = "mute_default_reason";
private static final String DURATION_PARAMETER = "duration";
private static final String MUTE_COMMAND = "mute";
private static final String USER_PARAMETER = "user";
private static final String REASON_PARAMETER = "reason";
private static final String MUTE_RESPONSE = "mute_response";
@Autowired @Autowired
private MuteService muteService; private MuteService muteService;
@@ -40,20 +48,28 @@ public class Mute extends AbstractConditionableCommand {
@Autowired @Autowired
private TemplateService templateService; private TemplateService templateService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
Member member = (Member) parameters.get(0); Member member = (Member) parameters.get(0);
if(!member.getGuild().equals(commandContext.getGuild())) { Guild guild = commandContext.getGuild();
GuildMessageChannel channel = commandContext.getChannel();
if(!member.getGuild().equals(guild)) {
throw new EntityGuildMismatchException(); throw new EntityGuildMismatchException();
} }
Duration duration = (Duration) parameters.get(1); Duration duration = (Duration) parameters.get(1);
String defaultReason = templateService.renderSimpleTemplate(MUTE_DEFAULT_REASON_TEMPLATE, commandContext.getGuild().getIdLong()); String defaultReason = templateService.renderSimpleTemplate(MUTE_DEFAULT_REASON_TEMPLATE, guild.getIdLong());
String reason = parameters.size() == 3 ? (String) parameters.get(2) : defaultReason; String reason = parameters.size() == 3 ? (String) parameters.get(2) : defaultReason;
ServerChannelMessage context = ServerChannelMessage ServerChannelMessage context = ServerChannelMessage
.builder() .builder()
.serverId(commandContext.getGuild().getIdLong()) .serverId(guild.getIdLong())
.channelId(commandContext.getChannel().getIdLong()) .channelId(channel.getIdLong())
.messageId(commandContext.getMessage().getIdLong()) .messageId(commandContext.getMessage().getIdLong())
.build(); .build();
MuteContext muteLogModel = MuteContext MuteContext muteLogModel = MuteContext
@@ -62,7 +78,7 @@ public class Mute extends AbstractConditionableCommand {
.muteTargetDate(Instant.now().plus(duration)) .muteTargetDate(Instant.now().plus(duration))
.mutedUser(member) .mutedUser(member)
.reason(reason) .reason(reason)
.contextChannel(commandContext.getChannel()) .contextChannel(channel)
.message(commandContext.getMessage()) .message(commandContext.getMessage())
.mutingUser(commandContext.getAuthor()) .mutingUser(commandContext.getAuthor())
.context(context) .context(context)
@@ -71,19 +87,87 @@ public class Mute extends AbstractConditionableCommand {
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Guild guild = event.getGuild();
GuildMessageChannel channel = event.getGuildChannel();
Member targetMember = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, Member.class);
String durationStr = slashCommandParameterService.getCommandOption(DURATION_PARAMETER, event, Duration.class, String.class);
Duration duration = ParseUtils.parseDuration(durationStr);
String reason;
if(slashCommandParameterService.hasCommandOption(REASON_PARAMETER, event)) {
reason = slashCommandParameterService.getCommandOption(REASON_PARAMETER, event, String.class);
} else {
reason = templateService.renderSimpleTemplate(MUTE_DEFAULT_REASON_TEMPLATE, guild.getIdLong());
}
ServerChannelMessage context = ServerChannelMessage
.builder()
.serverId(guild.getIdLong())
.channelId(channel.getIdLong())
.build();
MuteContext muteLogModel = MuteContext
.builder()
.muteDate(Instant.now())
.muteTargetDate(Instant.now().plus(duration))
.mutedUser(targetMember)
.reason(reason)
.contextChannel(channel)
.mutingUser(event.getMember())
.context(context)
.build();
return muteService.muteMemberWithLog(muteLogModel)
.thenCompose(unused -> interactionService.replyEmbed(MUTE_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter userParameter = Parameter
parameters.add(Parameter.builder().name("user").templated(true).type(Member.class).build()); .builder()
parameters.add(Parameter.builder().name("duration").templated(true).type(Duration.class).build()); .name(USER_PARAMETER)
parameters.add(Parameter.builder().name("reason").templated(true).type(String.class).optional(true).remainder(true).build()); .templated(true)
.type(Member.class)
.build();
Parameter durationParameter = Parameter
.builder()
.name(DURATION_PARAMETER)
.templated(true)
.type(Duration.class)
.build();
Parameter reasonParameter = Parameter
.builder()
.name(REASON_PARAMETER)
.templated(true)
.type(String.class)
.optional(true)
.remainder(true)
.build();
List<Parameter> parameters = Arrays.asList(userParameter, durationParameter, reasonParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build(); HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build();
List<EffectConfig> effectConfig = Arrays.asList(EffectConfig.builder().position(0).effectKey(MUTE_EFFECT_KEY).build()); EffectConfig muteEffect = EffectConfig
.builder()
.position(0)
.parameterName(USER_PARAMETER)
.effectKey(MUTE_EFFECT_KEY)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.MUTE)
.commandName("create")
.build();
List<EffectConfig> effectConfig = Arrays.asList(muteEffect);
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("mute") .name(MUTE_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.effects(effectConfig) .effects(effectConfig)
.causesReaction(true) .causesReaction(true)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -4,11 +4,13 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.PaginatorService; import dev.sheldan.abstracto.core.service.PaginatorService;
@@ -18,12 +20,14 @@ import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.converter.MuteEntryConverter; import dev.sheldan.abstracto.moderation.converter.MuteEntryConverter;
import dev.sheldan.abstracto.moderation.model.template.command.MuteEntry; import dev.sheldan.abstracto.moderation.model.template.command.MuteEntry;
import dev.sheldan.abstracto.moderation.model.template.command.MutesModel; import dev.sheldan.abstracto.moderation.model.template.command.MutesModel;
import dev.sheldan.abstracto.moderation.service.management.MuteManagementService; import dev.sheldan.abstracto.moderation.service.management.MuteManagementService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -37,6 +41,8 @@ public class Mutes extends AbstractConditionableCommand {
private static final String NO_MUTES_TEMPLATE_KEY = "mutes_no_mutes_found"; private static final String NO_MUTES_TEMPLATE_KEY = "mutes_no_mutes_found";
private static final String MUTES_DISPLAY_TEMPLATE_KEY = "mutes_display_response"; private static final String MUTES_DISPLAY_TEMPLATE_KEY = "mutes_display_response";
public static final String MUTES_COMMAND = "mutes";
public static final String MEMBER_PARAMETER = "member";
@Autowired @Autowired
private MuteManagementService muteManagementService; private MuteManagementService muteManagementService;
@@ -61,6 +67,12 @@ public class Mutes extends AbstractConditionableCommand {
@Autowired @Autowired
private PaginatorService paginatorService; private PaginatorService paginatorService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<dev.sheldan.abstracto.moderation.model.database.Mute> mutesToDisplay; List<dev.sheldan.abstracto.moderation.model.database.Mute> mutesToDisplay;
@@ -87,20 +99,74 @@ public class Mutes extends AbstractConditionableCommand {
@Transactional @Transactional
public CompletableFuture<Void> renderMutes(CommandContext commandContext, List<MuteEntry> mutes) { public CompletableFuture<Void> renderMutes(CommandContext commandContext, List<MuteEntry> mutes) {
MutesModel model = (MutesModel) ContextConverter.slimFromCommandContext(commandContext, MutesModel.class); MutesModel model = MutesModel
model.setMutes(mutes); .builder()
.mutes(mutes)
.build();
return paginatorService.createPaginatorFromTemplate(MUTES_DISPLAY_TEMPLATE_KEY, model, commandContext.getChannel(), commandContext.getAuthor().getIdLong()); return paginatorService.createPaginatorFromTemplate(MUTES_DISPLAY_TEMPLATE_KEY, model, commandContext.getChannel(), commandContext.getAuthor().getIdLong());
} }
@Transactional
public CompletableFuture<Void> renderMutes(SlashCommandInteractionEvent event, List<MuteEntry> mutes) {
MutesModel model = MutesModel
.builder()
.mutes(mutes)
.build();
return paginatorService.createPaginatorFromTemplate(MUTES_DISPLAY_TEMPLATE_KEY, model, event);
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
List<dev.sheldan.abstracto.moderation.model.database.Mute> mutesToDisplay;
if(!slashCommandParameterService.hasCommandOption(MEMBER_PARAMETER, event)) {
AServer server = serverManagementService.loadServer(event.getGuild().getIdLong());
mutesToDisplay = muteManagementService.getAllMutes(server);
} else {
Member memberParameter = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER, event, Member.class, Member.class);
if(!memberParameter.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
mutesToDisplay = muteManagementService.getAllMutesOf(userInServerManagementService.loadOrCreateUser(memberParameter));
}
if(mutesToDisplay.isEmpty()) {
MessageToSend messageToSend = templateService.renderEmbedTemplate(NO_MUTES_TEMPLATE_KEY, new Object(), event.getGuild().getIdLong());
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(unused -> CommandResult.fromSuccess());
} else {
return muteEntryConverter.fromMutes(mutesToDisplay)
.thenCompose(muteEntries -> self.renderMutes(event, muteEntries)
.thenApply(unused -> CommandResult.fromIgnored()));
}
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("member").templated(true).type(Member.class).optional(true).build()); Parameter memberParameter = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(MEMBER_PARAMETER)
.templated(true)
.type(Member.class)
.optional(true)
.build();
parameters.add(memberParameter);
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.MUTE)
.commandName("list")
.build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("mutes") .name(MUTES_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.async(true) .async(true)
.causesReaction(true) .causesReaction(true)

View File

@@ -4,28 +4,33 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.model.template.command.MyWarningsModel; import dev.sheldan.abstracto.moderation.model.template.command.MyWarningsModel;
import dev.sheldan.abstracto.moderation.service.management.WarnManagementService; import dev.sheldan.abstracto.moderation.service.management.WarnManagementService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component @Component
public class MyWarnings extends AbstractConditionableCommand { public class MyWarnings extends AbstractConditionableCommand {
public static final String MY_WARNINGS_RESPONSE_EMBED_TEMPLATE = "myWarnings_response"; public static final String MY_WARNINGS_RESPONSE_EMBED_TEMPLATE = "myWarnings_response";
private static final String MY_WARNINGS_COMMAND = "myWarnings";
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@@ -35,27 +40,57 @@ public class MyWarnings extends AbstractConditionableCommand {
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
MyWarningsModel model = (MyWarningsModel) ContextConverter.fromCommandContext(commandContext, MyWarningsModel.class);
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor()); AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor());
Long currentWarnCount = warnManagementService.getActiveWarnCountForUser(userInAServer); Long currentWarnCount = warnManagementService.getActiveWarnCountForUser(userInAServer);
model.setCurrentWarnCount(currentWarnCount);
Long totalWarnCount = warnManagementService.getTotalWarnsForUser(userInAServer); Long totalWarnCount = warnManagementService.getTotalWarnsForUser(userInAServer);
model.setTotalWarnCount(totalWarnCount); MyWarningsModel model = MyWarningsModel
.builder()
.member(commandContext.getAuthor())
.totalWarnCount(totalWarnCount)
.currentWarnCount(currentWarnCount)
.build();
channelService.sendEmbedTemplateInTextChannelList(MY_WARNINGS_RESPONSE_EMBED_TEMPLATE, model, commandContext.getChannel()); channelService.sendEmbedTemplateInTextChannelList(MY_WARNINGS_RESPONSE_EMBED_TEMPLATE, model, commandContext.getChannel());
return CommandResult.fromIgnored(); return CommandResult.fromIgnored();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(event.getMember());
Long currentWarnCount = warnManagementService.getActiveWarnCountForUser(userInAServer);
Long totalWarnCount = warnManagementService.getTotalWarnsForUser(userInAServer);
MyWarningsModel model = MyWarningsModel
.builder()
.member(event.getMember())
.totalWarnCount(totalWarnCount)
.currentWarnCount(currentWarnCount)
.build();
return interactionService.replyEmbed(MY_WARNINGS_RESPONSE_EMBED_TEMPLATE, model, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
List<String> aliases = Arrays.asList("myWarns"); List<String> aliases = Arrays.asList("myWarns");
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.WARNINGS_PUBLIC)
.commandName(MY_WARNINGS_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("myWarnings") .name(MY_WARNINGS_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)
.aliases(aliases) .aliases(aliases)

View File

@@ -1,19 +1,21 @@
package dev.sheldan.abstracto.moderation.command; package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.ParameterValidator;
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator; import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.utils.SnowflakeUtils;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.PurgeService; import dev.sheldan.abstracto.moderation.service.PurgeService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -25,9 +27,20 @@ import java.util.concurrent.CompletableFuture;
@Component @Component
public class Purge extends AbstractConditionableCommand { public class Purge extends AbstractConditionableCommand {
private static final String AMOUNT_PARAMETER = "amount";
private static final String MEMBER_PARAMETER = "member";
private static final String PURGE_COMMAND = "purge";
private static final String PURGE_INITIAL_MESSAGE = "purge_initial_message";
@Autowired @Autowired
private PurgeService purgeService; private PurgeService purgeService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
Integer amountOfMessages = (Integer) commandContext.getParameters().getParameters().get(0); Integer amountOfMessages = (Integer) commandContext.getParameters().getParameters().get(0);
@@ -42,17 +55,62 @@ public class Purge extends AbstractConditionableCommand {
.thenApply(aVoid -> CommandResult.fromSelfDestruct()); .thenApply(aVoid -> CommandResult.fromSelfDestruct());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Integer amountOfMessages = slashCommandParameterService.getCommandOption(AMOUNT_PARAMETER, event, Integer.class);
Member memberToPurgeMessagesOf;
if(slashCommandParameterService.hasCommandOption(MEMBER_PARAMETER, event)) {
memberToPurgeMessagesOf = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER, event, Member.class);
if(!memberToPurgeMessagesOf.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
} else {
memberToPurgeMessagesOf = null;
}
return interactionService.replyEmbed(PURGE_INITIAL_MESSAGE, event)
.thenCompose(interactionHook -> {
Long startMessageId = SnowflakeUtils.createSnowFlake();
return purgeService.purgeMessagesInChannel(amountOfMessages, event.getGuildChannel(), startMessageId , event.getHook(), memberToPurgeMessagesOf);
}).thenApply(unused -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
List<ParameterValidator> messageAmountValidator = Arrays.asList(MinIntegerValueValidator.min(1L)); List<ParameterValidator> messageAmountValidator = Arrays.asList(MinIntegerValueValidator.min(1L));
parameters.add(Parameter.builder().name("amount").validators(messageAmountValidator).type(Integer.class).templated(true).build()); Parameter amountParameter = Parameter
parameters.add(Parameter.builder().name("member").type(Member.class).optional(true).templated(true).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .name(AMOUNT_PARAMETER)
.validators(messageAmountValidator)
.type(Integer.class)
.templated(true)
.build();
parameters.add(amountParameter);
Parameter memberParameter = Parameter
.builder()
.name(MEMBER_PARAMETER)
.type(Member.class)
.optional(true)
.templated(true)
.build();
parameters.add(memberParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.MODERATION)
.commandName(PURGE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("purge") .name(PURGE_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true) .async(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)

View File

@@ -4,29 +4,45 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.utils.ParseUtils; import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.SlowModeService; import dev.sheldan.abstracto.moderation.service.SlowModeService;
import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
public class SlowMode extends AbstractConditionableCommand { public class SlowMode extends AbstractConditionableCommand {
private static final String CHANNEL_PARAMETER = "channel";
private static final String DURATION_PARAMETER = "duration";
private static final String SLOWMODE_COMMAND = "slowmode";
private static final String SLOWMODE_RESPONSE = "slowmode_response";
@Autowired @Autowired
private SlowModeService slowModeService; private SlowModeService slowModeService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
TextChannel channel; TextChannel channel;
@@ -53,16 +69,68 @@ public class SlowMode extends AbstractConditionableCommand {
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
TextChannel channel;
String durationString = slashCommandParameterService.getCommandOption(DURATION_PARAMETER, event, String.class);
Duration duration;
if(durationString.equalsIgnoreCase("off")) {
duration = Duration.ZERO;
} else {
duration = ParseUtils.parseDuration(durationString);
}
if(slashCommandParameterService.hasCommandOption(CHANNEL_PARAMETER, event)) {
channel = slashCommandParameterService.getCommandOption(CHANNEL_PARAMETER, event, TextChannel.class);
if(!channel.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
} else {
if(event.getChannel() instanceof TextChannel) {
channel = (TextChannel) event.getChannel();
} else {
throw new IllegalArgumentException("Not a text channel.");
}
}
return slowModeService.setSlowMode(channel, duration)
.thenCompose(unused -> interactionService.replyEmbed(SLOWMODE_RESPONSE, event))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("duration").type(String.class).templated(true).build()); Parameter durationParameter = Parameter
parameters.add(Parameter.builder().name("channel").type(TextChannel.class).templated(true).optional(true).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build(); .name(DURATION_PARAMETER)
.type(String.class)
.templated(true)
.build();
Parameter channelParameter = Parameter
.builder()
.name(CHANNEL_PARAMETER)
.type(TextChannel.class)
.templated(true)
.optional(true)
.build();
List<Parameter> parameters = Arrays.asList(durationParameter, channelParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.hasExample(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.MODERATION)
.commandName(SLOWMODE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("slowmode") .name(SLOWMODE_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true) .async(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)

View File

@@ -5,15 +5,19 @@ import dev.sheldan.abstracto.core.command.condition.CommandCondition;
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.BanService; import dev.sheldan.abstracto.moderation.service.BanService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -24,30 +28,70 @@ import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j @Slf4j
public class UnBan extends AbstractConditionableCommand { public class UnBan extends AbstractConditionableCommand {
private static final String USER_PARAMETER = "user";
private static final String UN_BAN_COMMAND = "unBan";
private static final String UN_BAN_RESPONSE = "unBan_response";
@Autowired @Autowired
private BanService banService; private BanService banService;
@Autowired @Autowired
private TemplateService templateService; private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Autowired
private UserService userService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
User user = (User) parameters.get(0); String userIdStr = (String) parameters.get(0);
return banService.unBanUserWithNotification(user, commandContext.getAuthor()) Long userId = Long.parseLong(userIdStr);
return userService.retrieveUserForId(userId)
.thenCompose(user -> banService.unBanUserWithNotification(user, commandContext.getAuthor()))
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String userIdStr = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, String.class);
Long userId = Long.parseLong(userIdStr);
return userService.retrieveUserForId(userId)
.thenCompose(user -> banService.unBanUserWithNotification(user, event.getMember()))
.thenCompose(unused -> interactionService.replyEmbed(UN_BAN_RESPONSE, event))
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("user").templated(true).type(User.class).build()); Parameter userParameter = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(USER_PARAMETER)
.templated(true)
.type(String.class)
.build();
parameters.add(userParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.MODERATION)
.commandName(UN_BAN_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("unBan") .name(UN_BAN_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)
.parameters(parameters) .parameters(parameters)

View File

@@ -4,32 +4,43 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.MuteService; import dev.sheldan.abstracto.moderation.service.MuteService;
import dev.sheldan.abstracto.moderation.service.management.MuteManagementService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
public class UnMute extends AbstractConditionableCommand { public class UnMute extends AbstractConditionableCommand {
private static final String UN_MUTE_COMMAND = "unMute";
private static final String USER_PARAMETER = "user";
private static final String UN_MUTE_RESPONSE = "unMute_response";
@Autowired @Autowired
private MuteService muteService; private MuteService muteService;
@Autowired @Autowired
private MuteManagementService muteManagementService; private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@@ -47,16 +58,45 @@ public class UnMute extends AbstractConditionableCommand {
); );
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member targetMember = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, Member.class);
if(!targetMember.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
AUserInAServer userToUnMute = userInServerManagementService.loadOrCreateUser(targetMember);
return muteService.unMuteUser(userToUnMute)
.thenCompose(unused -> interactionService.replyEmbed(UN_MUTE_RESPONSE, event))
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter userParameter = Parameter
parameters.add(Parameter.builder().name("user").type(Member.class).templated(true).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .name(USER_PARAMETER)
.type(Member.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(userParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.MUTE)
.commandName("remove")
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("unMute") .name(UN_MUTE_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)
.parameters(parameters) .parameters(parameters)

View File

@@ -4,31 +4,48 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.service.management.UserNoteManagementService; import dev.sheldan.abstracto.moderation.service.management.UserNoteManagementService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component @Component
public class UserNoteCommand extends AbstractConditionableCommand { public class UserNoteCommand extends AbstractConditionableCommand {
private static final String USER_PARAMETER = "user";
private static final String TEXT_PARAMETER = "text";
private static final String USER_NOTE_COMMAND = "userNote";
private static final String USER_NOTE_RESPONSE = "userNote_response";
@Autowired @Autowired
private UserNoteManagementService userNoteManagementService; private UserNoteManagementService userNoteManagementService;
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
@@ -42,14 +59,50 @@ public class UserNoteCommand extends AbstractConditionableCommand {
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member member = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, Member.class);
if(!member.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
String text = slashCommandParameterService.getCommandOption(TEXT_PARAMETER, event, String.class);
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(member);
userNoteManagementService.createUserNote(userInAServer, text);
return interactionService.replyEmbed(USER_NOTE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter userParameter = Parameter
parameters.add(Parameter.builder().name("user").type(Member.class).templated(true).build()); .builder()
parameters.add(Parameter.builder().name("text").type(String.class).templated(true).remainder(true).build()); .name(USER_PARAMETER)
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .type(Member.class)
.templated(true)
.build();
Parameter textParameter = Parameter
.builder()
.name(TEXT_PARAMETER)
.type(String.class)
.templated(true)
.remainder(true)
.build();
List<Parameter> parameters = Arrays.asList(userParameter, textParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.USER_NOTES)
.commandName("create")
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("userNote") .name(USER_NOTE_COMMAND)
.slashCommandConfig(slashCommandConfig)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -4,11 +4,13 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.FullUserInServer; import dev.sheldan.abstracto.core.models.FullUserInServer;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
@@ -17,6 +19,7 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.converter.UserNotesConverter; import dev.sheldan.abstracto.moderation.converter.UserNotesConverter;
import dev.sheldan.abstracto.moderation.model.database.UserNote; import dev.sheldan.abstracto.moderation.model.database.UserNote;
@@ -24,6 +27,7 @@ import dev.sheldan.abstracto.moderation.model.template.command.ListNotesModel;
import dev.sheldan.abstracto.moderation.model.template.command.NoteEntryModel; import dev.sheldan.abstracto.moderation.model.template.command.NoteEntryModel;
import dev.sheldan.abstracto.moderation.service.management.UserNoteManagementService; import dev.sheldan.abstracto.moderation.service.management.UserNoteManagementService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -34,6 +38,8 @@ import java.util.concurrent.CompletableFuture;
@Component @Component
public class UserNotes extends AbstractConditionableCommand { public class UserNotes extends AbstractConditionableCommand {
public static final String USER_NOTES_RESPONSE_TEMPLATE = "user_notes_response"; public static final String USER_NOTES_RESPONSE_TEMPLATE = "user_notes_response";
public static final String USER_NOTES_COMMAND = "userNotes";
public static final String USER_PARAMETER = "user";
@Autowired @Autowired
private UserNoteManagementService userNoteManagementService; private UserNoteManagementService userNoteManagementService;
@@ -49,12 +55,21 @@ public class UserNotes extends AbstractConditionableCommand {
@Autowired @Autowired
private ServerManagementService serverManagementService; private ServerManagementService serverManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
List<UserNote> userNotes; List<UserNote> userNotes;
ListNotesModel model = (ListNotesModel) ContextConverter.fromCommandContext(commandContext, ListNotesModel.class); ListNotesModel model = ListNotesModel
.builder()
.member(commandContext.getAuthor())
.build();
if(parameters.size() == 1) { if(parameters.size() == 1) {
Member member = (Member) parameters.get(0); Member member = (Member) parameters.get(0);
if(!member.getGuild().equals(commandContext.getGuild())) { if(!member.getGuild().equals(commandContext.getGuild())) {
@@ -80,17 +95,68 @@ public class UserNotes extends AbstractConditionableCommand {
}); });
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
List<UserNote> userNotes;
ListNotesModel model = ListNotesModel
.builder()
.member(event.getMember())
.build();
if(slashCommandParameterService.hasCommandOption(USER_PARAMETER, event)) {
Member member = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, Member.class);
if(!member.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
AUserInAServer userInAServer = userInServerManagementService.loadOrCreateUser(member);
userNotes = userNoteManagementService.loadNotesForUser(userInAServer);
FullUserInServer specifiedUser = FullUserInServer
.builder()
.aUserInAServer(userInAServer)
.member(member)
.build();
model.setSpecifiedUser(specifiedUser);
} else {
AServer server = serverManagementService.loadServer(event.getGuild());
userNotes = userNoteManagementService.loadNotesForServer(server);
}
CompletableFuture<List<NoteEntryModel>> listCompletableFuture = userNotesConverter.fromNotes(userNotes);
return listCompletableFuture.thenCompose(noteEntryModels -> {
model.setUserNotes(noteEntryModels);
return interactionService.replyEmbed(USER_NOTES_RESPONSE_TEMPLATE, model, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
});
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
Parameter user = Parameter.builder().name("user").type(Member.class).optional(true).templated(true).build(); Parameter user = Parameter
.builder()
.name(USER_PARAMETER)
.type(Member.class)
.optional(true)
.templated(true)
.build();
parameters.add(user); parameters.add(user);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.USER_NOTES)
.commandName("list")
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("userNotes") .name(USER_NOTES_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)
.parameters(parameters) .parameters(parameters)

View File

@@ -2,26 +2,25 @@ package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.condition.CommandCondition; import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.config.EffectConfig;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.model.template.command.WarnContext; import dev.sheldan.abstracto.moderation.model.template.command.WarnContext;
import dev.sheldan.abstracto.moderation.service.WarnService; import dev.sheldan.abstracto.moderation.service.WarnService;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -33,12 +32,23 @@ import static dev.sheldan.abstracto.moderation.service.WarnService.WARN_EFFECT_K
public class Warn extends AbstractConditionableCommand { public class Warn extends AbstractConditionableCommand {
public static final String WARN_DEFAULT_REASON_TEMPLATE = "warn_default_reason"; public static final String WARN_DEFAULT_REASON_TEMPLATE = "warn_default_reason";
private static final String WARN_COMMAND = "warn";
private static final String USER_PARAMETER = "user";
private static final String REASON_PARAMETER = "reason";
private static final String WARN_RESPONSE = "warn_response";
@Autowired @Autowired
private WarnService warnService; private WarnService warnService;
@Autowired @Autowired
private TemplateService templateService; private TemplateService templateService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
@@ -48,25 +58,87 @@ public class Warn extends AbstractConditionableCommand {
} }
String defaultReason = templateService.renderSimpleTemplate(WARN_DEFAULT_REASON_TEMPLATE, commandContext.getGuild().getIdLong()); String defaultReason = templateService.renderSimpleTemplate(WARN_DEFAULT_REASON_TEMPLATE, commandContext.getGuild().getIdLong());
String reason = parameters.size() == 2 ? (String) parameters.get(1) : defaultReason; String reason = parameters.size() == 2 ? (String) parameters.get(1) : defaultReason;
WarnContext warnLogModel = (WarnContext) ContextConverter.slimFromCommandContext(commandContext, WarnContext.class); WarnContext warnLogModel = WarnContext
warnLogModel.setReason(reason); .builder()
warnLogModel.setWarnedMember(member); .reason(reason)
.warnedMember(member)
.member(commandContext.getAuthor())
.guild(commandContext.getGuild())
.message(commandContext.getMessage())
.build();
return warnService.warnUserWithLog(warnLogModel) return warnService.warnUserWithLog(warnLogModel)
.thenApply(warning -> CommandResult.fromSuccess()); .thenApply(warning -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member member = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, Member.class);
if(!member.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
String reason;
if(slashCommandParameterService.hasCommandOption(REASON_PARAMETER, event)) {
reason = slashCommandParameterService.getCommandOption(REASON_PARAMETER, event, String.class);
} else {
reason = templateService.renderSimpleTemplate(WARN_DEFAULT_REASON_TEMPLATE, event.getGuild().getIdLong());
}
WarnContext warnLogModel = WarnContext
.builder()
.reason(reason)
.warnedMember(member)
.member(event.getMember())
.channel(event.getGuildChannel())
.guild(event.getGuild())
.build();
return warnService.warnUserWithLog(warnLogModel)
.thenCompose(unused -> interactionService.replyEmbed(WARN_RESPONSE, event))
.thenApply(warning -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("user").type(Member.class).templated(true).build()); Parameter userParameter = Parameter
parameters.add(Parameter.builder().name("reason").type(String.class).templated(true).optional(true).remainder(true).build()); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build(); .name(USER_PARAMETER)
List<EffectConfig> effectConfig = Arrays.asList(EffectConfig.builder().position(0).effectKey(WARN_EFFECT_KEY).build()); .type(Member.class)
.templated(true)
.build();
Parameter reasonParameter = Parameter
.builder()
.name(REASON_PARAMETER)
.type(String.class)
.templated(true)
.optional(true)
.remainder(true)
.build();
HelpInfo helpInfo = HelpInfo
.builder().
templated(true)
.hasExample(true)
.build();
List<Parameter> parameters = Arrays.asList(userParameter, reasonParameter);
EffectConfig warnEffect = EffectConfig
.builder()
.position(0)
.parameterName(USER_PARAMETER)
.effectKey(WARN_EFFECT_KEY)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.WARNINGS)
.commandName("create")
.build();
List<EffectConfig> effectConfig = Arrays.asList(warnEffect);
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("warn") .name(WARN_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.async(true) .async(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)
.effects(effectConfig) .effects(effectConfig)

View File

@@ -4,11 +4,13 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.PaginatorService; import dev.sheldan.abstracto.core.service.PaginatorService;
@@ -18,6 +20,7 @@ import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition; import dev.sheldan.abstracto.moderation.config.ModerationModuleDefinition;
import dev.sheldan.abstracto.moderation.config.ModerationSlashCommandNames;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.converter.WarnEntryConverter; import dev.sheldan.abstracto.moderation.converter.WarnEntryConverter;
import dev.sheldan.abstracto.moderation.model.database.Warning; import dev.sheldan.abstracto.moderation.model.database.Warning;
@@ -25,6 +28,7 @@ import dev.sheldan.abstracto.moderation.model.template.command.WarnEntry;
import dev.sheldan.abstracto.moderation.model.template.command.WarningsModel; import dev.sheldan.abstracto.moderation.model.template.command.WarningsModel;
import dev.sheldan.abstracto.moderation.service.management.WarnManagementService; import dev.sheldan.abstracto.moderation.service.management.WarnManagementService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -38,6 +42,8 @@ public class Warnings extends AbstractConditionableCommand {
public static final String WARNINGS_RESPONSE_TEMPLATE = "warnings_display_response"; public static final String WARNINGS_RESPONSE_TEMPLATE = "warnings_display_response";
public static final String NO_WARNINGS_TEMPLATE_KEY = "warnings_no_warnings_found"; public static final String NO_WARNINGS_TEMPLATE_KEY = "warnings_no_warnings_found";
public static final String WARNINGS_COMMAND = "warnings";
public static final String USER_PARAMETER = "user";
@Autowired @Autowired
private WarnManagementService warnManagementService; private WarnManagementService warnManagementService;
@@ -62,6 +68,12 @@ public class Warnings extends AbstractConditionableCommand {
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Warning> warnsToDisplay; List<Warning> warnsToDisplay;
@@ -85,29 +97,83 @@ public class Warnings extends AbstractConditionableCommand {
.thenCompose(warnEntries -> self.renderWarnings(commandContext, warnEntries)) .thenCompose(warnEntries -> self.renderWarnings(commandContext, warnEntries))
.thenApply(unused -> CommandResult.fromIgnored()); .thenApply(unused -> CommandResult.fromIgnored());
} }
} }
@Transactional @Transactional
public CompletableFuture<Void> renderWarnings(CommandContext commandContext, List<WarnEntry> warnEntries) { public CompletableFuture<Void> renderWarnings(CommandContext commandContext, List<WarnEntry> warnEntries) {
WarningsModel model = (WarningsModel) ContextConverter.slimFromCommandContext(commandContext, WarningsModel.class); WarningsModel model = WarningsModel
model.setWarnings(warnEntries); .builder()
.warnings(warnEntries)
.build();
return paginatorService.createPaginatorFromTemplate(WARNINGS_RESPONSE_TEMPLATE, model, commandContext.getChannel(), commandContext.getAuthor().getIdLong()); return paginatorService.createPaginatorFromTemplate(WARNINGS_RESPONSE_TEMPLATE, model, commandContext.getChannel(), commandContext.getAuthor().getIdLong());
} }
@Transactional
public CompletableFuture<Void> renderWarnings(SlashCommandInteractionEvent event, List<WarnEntry> warnEntries) {
WarningsModel model = WarningsModel
.builder()
.warnings(warnEntries)
.build();
return paginatorService.createPaginatorFromTemplate(WARNINGS_RESPONSE_TEMPLATE, model, event);
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
List<Warning> warnsToDisplay;
if(slashCommandParameterService.hasCommandOption(USER_PARAMETER, event)) {
Member member = slashCommandParameterService.getCommandOption(USER_PARAMETER, event, Member.class);
if(!member.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
warnsToDisplay = warnManagementService.getAllWarnsForUser(userInServerManagementService.loadOrCreateUser(member));
} else {
AServer server = serverManagementService.loadServer(event.getGuild());
warnsToDisplay = warnManagementService.getAllWarningsOfServer(server);
}
if(warnsToDisplay.isEmpty()) {
MessageToSend messageToSend = templateService.renderEmbedTemplate(NO_WARNINGS_TEMPLATE_KEY, new Object(), event.getGuild().getIdLong());
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
} else {
return warnEntryConverter.fromWarnings(warnsToDisplay)
.thenCompose(warnEntries -> self.renderWarnings(event, warnEntries))
.thenApply(unused -> CommandResult.fromIgnored());
}
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("user").type(Member.class).templated(true).optional(true).build()); Parameter userParameter = Parameter
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .builder()
.name(USER_PARAMETER)
.type(Member.class)
.templated(true)
.optional(true)
.build();
parameters.add(userParameter);
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModerationSlashCommandNames.WARNINGS)
.commandName("list")
.build();
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("warnings") .name(WARNINGS_COMMAND)
.module(ModerationModuleDefinition.MODERATION) .module(ModerationModuleDefinition.MODERATION)
.templated(true) .templated(true)
.async(true) .async(true)
.causesReaction(false) .causesReaction(false)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.parameters(parameters) .parameters(parameters)
.help(helpInfo) .help(helpInfo)

View File

@@ -8,6 +8,7 @@ import org.springframework.lang.NonNull;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List; import java.util.List;
import java.util.Optional;
@Repository @Repository
public interface UserNoteRepository extends JpaRepository<UserNote, Long> { public interface UserNoteRepository extends JpaRepository<UserNote, Long> {
@@ -19,6 +20,6 @@ public interface UserNoteRepository extends JpaRepository<UserNote, Long> {
void deleteByUserNoteId_IdAndUserNoteId_ServerId(@NonNull Long aLong, Long serverId); void deleteByUserNoteId_IdAndUserNoteId_ServerId(@NonNull Long aLong, Long serverId);
UserNote findByUserNoteId_IdAndUserNoteId_ServerId(Long userNoteId, Long serverId); Optional<UserNote> findByUserNoteId_IdAndUserNoteId_ServerId(Long userNoteId, Long serverId);
} }

View File

@@ -5,14 +5,12 @@ import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.moderation.config.posttarget.ModerationPostTarget; import dev.sheldan.abstracto.moderation.config.posttarget.ModerationPostTarget;
import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.moderation.model.BanResult;
import dev.sheldan.abstracto.moderation.model.template.command.BanLog; import dev.sheldan.abstracto.moderation.model.template.command.BanLog;
import dev.sheldan.abstracto.moderation.model.template.command.BanNotificationModel; import dev.sheldan.abstracto.moderation.model.template.command.BanNotificationModel;
import dev.sheldan.abstracto.moderation.model.template.command.UnBanLog; import dev.sheldan.abstracto.moderation.model.template.command.UnBanLog;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -26,10 +24,6 @@ public class BanServiceBean implements BanService {
public static final String BAN_LOG_TEMPLATE = "ban_log"; public static final String BAN_LOG_TEMPLATE = "ban_log";
public static final String UN_BAN_LOG_TEMPLATE = "unBan_log"; public static final String UN_BAN_LOG_TEMPLATE = "unBan_log";
public static final String BAN_NOTIFICATION = "ban_notification"; public static final String BAN_NOTIFICATION = "ban_notification";
public static final String BAN_NOTIFICATION_NOT_POSSIBLE = "ban_notification_not_possible";
@Autowired
private GuildService guildService;
@Autowired @Autowired
private TemplateService templateService; private TemplateService templateService;
@@ -37,63 +31,33 @@ public class BanServiceBean implements BanService {
@Autowired @Autowired
private PostTargetService postTargetService; private PostTargetService postTargetService;
@Autowired
private FeatureModeService featureModeService;
@Autowired @Autowired
private BanServiceBean self; private BanServiceBean self;
@Autowired @Autowired
private MessageService messageService; private MessageService messageService;
@Autowired
private ChannelService channelService;
@Override @Override
public CompletableFuture<Void> banMemberWithNotification(Member member, String reason, Member banningMember, Integer deletionDays, Message message) { public CompletableFuture<BanResult> banUserWithNotification(User user, String reason, Member banningMember, Integer deletionDays) {
BanLog banLog = BanLog
.builder()
.bannedUser(member.getUser())
.banningMember(banningMember)
.commandMessage(message)
.reason(reason)
.build();
CompletableFuture<Void> banFuture = banUser(member.getGuild(), member.getUser(), deletionDays, reason);
CompletableFuture<Void> messageFuture = sendBanLogMessage(banLog, member.getGuild().getIdLong(), BAN_LOG_TEMPLATE);
return CompletableFuture.allOf(banFuture, messageFuture);
}
@Override
public CompletableFuture<Void> banUserWithNotification(User user, String reason, Member banningMember, Integer deletionDays, Message message) {
BanLog banLog = BanLog BanLog banLog = BanLog
.builder() .builder()
.bannedUser(user) .bannedUser(user)
.banningMember(banningMember) .banningMember(banningMember)
.commandMessage(message)
.deletionDays(deletionDays) .deletionDays(deletionDays)
.reason(reason) .reason(reason)
.build(); .build();
Guild guild = banningMember.getGuild(); Guild guild = banningMember.getGuild();
CompletableFuture<Void> returningFuture = new CompletableFuture<>(); CompletableFuture<BanResult> returningFuture = new CompletableFuture<>();
sendBanNotification(user, reason, message.getGuild()).whenComplete((unused, throwable) -> { sendBanNotification(user, reason, guild)
if(throwable != null) { .whenComplete((unused, throwable) -> banUser(guild, user, deletionDays, reason)
String errorNotification = templateService.renderSimpleTemplate(BAN_NOTIFICATION_NOT_POSSIBLE, guild.getIdLong()); .thenCompose(unused1 -> sendBanLogMessage(banLog, guild.getIdLong()))
channelService.sendTextToChannel(errorNotification, message.getChannel()) .thenAccept(unused1 -> {
.thenAccept(message1 -> log.info("Notified about not being able to send ban notification in server {} and channel {} based on message {} from user {}." if(throwable != null) {
, message.getGuild().getIdLong(), message.getChannel().getIdLong(), message.getIdLong(), message.getAuthor().getIdLong())); returningFuture.complete(BanResult.NOTIFICATION_FAILED);
} } else {
CompletableFuture<Void> banFuture = banUser(guild, user, deletionDays, reason); returningFuture.complete(BanResult.SUCCESSFUL);
CompletableFuture<Void> messageFuture = sendBanLogMessage(banLog, guild.getIdLong(), BAN_LOG_TEMPLATE); }
CompletableFuture.allOf(banFuture, messageFuture) }));
.thenAccept(unused1 -> returningFuture.complete(null))
.exceptionally(throwable1 -> {
returningFuture.completeExceptionally(throwable1);
return null;
});
}).exceptionally(throwable -> {
returningFuture.completeExceptionally(throwable);
return null;
});
return returningFuture; return returningFuture;
} }
@@ -138,8 +102,8 @@ public class BanServiceBean implements BanService {
.thenCompose(unused -> unbanUser(guild, user)); .thenCompose(unused -> unbanUser(guild, user));
} }
public CompletableFuture<Void> sendBanLogMessage(BanLog banLog, Long guildId, String template) { public CompletableFuture<Void> sendBanLogMessage(BanLog banLog, Long guildId) {
MessageToSend banLogMessage = templateService.renderEmbedTemplate(template, banLog, guildId); MessageToSend banLogMessage = templateService.renderEmbedTemplate(BAN_LOG_TEMPLATE, banLog, guildId);
log.debug("Sending ban log message in guild {}.", guildId); log.debug("Sending ban log message in guild {}.", guildId);
return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(banLogMessage, ModerationPostTarget.BAN_LOG, guildId)); return FutureUtils.toSingleFutureGeneric(postTargetService.sendEmbedInPostTarget(banLogMessage, ModerationPostTarget.BAN_LOG, guildId));
} }

View File

@@ -27,9 +27,6 @@ public class KickServiceBean implements KickService {
@Autowired @Autowired
private PostTargetService postTargetService; private PostTargetService postTargetService;
@Autowired
private FeatureModeService featureModeService;
@Override @Override
public CompletableFuture<Void> kickMember(Member member, String reason, KickLogModel kickLogModel) { public CompletableFuture<Void> kickMember(Member member, String reason, KickLogModel kickLogModel) {
Guild guild = member.getGuild(); Guild guild = member.getGuild();

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.moderation.service; package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.metric.service.CounterMetric; import dev.sheldan.abstracto.core.metric.service.CounterMetric;
import dev.sheldan.abstracto.core.metric.service.MetricService; import dev.sheldan.abstracto.core.metric.service.MetricService;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
@@ -10,6 +11,8 @@ import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.utils.MiscUtil; import net.dv8tion.jda.api.utils.MiscUtil;
import net.dv8tion.jda.api.utils.TimeUtil; import net.dv8tion.jda.api.utils.TimeUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -19,6 +22,7 @@ import javax.annotation.PostConstruct;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -39,6 +43,9 @@ public class PurgeServiceBean implements PurgeService {
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@Autowired
private InteractionService interactionService;
public static final String MODERATION_PURGE_METRIC = "moderation.purge"; public static final String MODERATION_PURGE_METRIC = "moderation.purge";
private static final CounterMetric PURGE_MESSAGE_COUNTER_METRIC = private static final CounterMetric PURGE_MESSAGE_COUNTER_METRIC =
@@ -119,9 +126,9 @@ public class PurgeServiceBean implements PurgeService {
private CompletableFuture<Long> getOrCreatedStatusMessage(GuildMessageChannel channel, Integer totalCount, Long statusMessageId) { private CompletableFuture<Long> getOrCreatedStatusMessage(GuildMessageChannel channel, Integer totalCount, Long statusMessageId) {
CompletableFuture<Long> statusMessageFuture; CompletableFuture<Long> statusMessageFuture;
if(statusMessageId == 0) { if(statusMessageId == 0) {
Long serverId = channel.getGuild().getIdLong();
log.debug("Creating new status message in channel {} in server {} because of puring.", channel.getIdLong(), channel.getGuild().getId()); log.debug("Creating new status message in channel {} in server {} because of puring.", channel.getIdLong(), channel.getGuild().getId());
PurgeStatusUpdateModel model = PurgeStatusUpdateModel.builder().currentlyDeleted(0).totalToDelete(totalCount).build(); MessageToSend messageToSend = getStatusMessageToSend(totalCount, serverId, 0);
MessageToSend messageToSend = templateService.renderTemplateToMessageToSend("purge_status_update", model, channel.getGuild().getIdLong());
statusMessageFuture = messageService.createStatusMessageId(messageToSend, channel); statusMessageFuture = messageService.createStatusMessageId(messageToSend, channel);
} else { } else {
log.debug("Using existing status message {}.", statusMessageId); log.debug("Using existing status message {}.", statusMessageId);
@@ -130,6 +137,15 @@ public class PurgeServiceBean implements PurgeService {
return statusMessageFuture; return statusMessageFuture;
} }
private MessageToSend getStatusMessageToSend(Integer totalCount, Long serverId, Integer currentlyDeleted) {
PurgeStatusUpdateModel model = PurgeStatusUpdateModel
.builder()
.currentlyDeleted(currentlyDeleted)
.totalToDelete(totalCount)
.build();
return templateService.renderTemplateToMessageToSend("purge_status_update", model, serverId);
}
private List<Message> filterMessagesToDelete(List<Message> retrievedHistory, Member purgedMember) { private List<Message> filterMessagesToDelete(List<Message> retrievedHistory, Member purgedMember) {
long twoWeeksAgo = TimeUtil.getDiscordTimestamp((System.currentTimeMillis() - (14 * 24 * 60 * 60 * 1000))); long twoWeeksAgo = TimeUtil.getDiscordTimestamp((System.currentTimeMillis() - (14 * 24 * 60 * 60 * 1000)));
log.debug("Filtering messages older than {}.", twoWeeksAgo); log.debug("Filtering messages older than {}.", twoWeeksAgo);
@@ -174,17 +190,96 @@ public class PurgeServiceBean implements PurgeService {
deletionFuture.complete(null); deletionFuture.complete(null);
} }
log.debug("Setting status for {} out of {}", currentCount, totalCount); log.debug("Setting status for {} out of {}", currentCount, totalCount);
PurgeStatusUpdateModel finalUpdateModel = PurgeStatusUpdateModel.builder().currentlyDeleted(currentCount).totalToDelete(totalCount).build(); MessageToSend finalUpdateMessage = getStatusMessageToSend(totalCount, channel.getGuild().getIdLong(), currentCount);
MessageToSend finalUpdateMessage = templateService.renderTemplateToMessageToSend("purge_status_update", finalUpdateModel);
messageService.updateStatusMessage(channel, currentStatusMessageId, finalUpdateMessage); messageService.updateStatusMessage(channel, currentStatusMessageId, finalUpdateMessage);
}; };
} }
private Consumer<Void> deletionConsumer(Integer amountToDelete, GuildMessageChannel channel, Member purgedMember, Integer totalCount, Integer currentCount, CompletableFuture<Void> deletionFuture, InteractionHook interactionHook, Message earliestMessage) {
return aVoid -> {
if (amountToDelete >= 1) {
log.debug("Still more than 1 message to delete. Continuing.");
purgeMessages(amountToDelete, channel, earliestMessage.getIdLong(), purgedMember, totalCount, currentCount, interactionHook)
.whenComplete((avoid, throwable) -> {
if (throwable != null) {
deletionFuture.completeExceptionally(throwable);
} else {
deletionFuture.complete(null);
}
}
).exceptionally(throwable -> {
deletionFuture.completeExceptionally(throwable);
return null;
});
} else {
log.debug("Completed purging of {} messages.", totalCount);
deletionFuture.complete(null);
}
log.debug("Setting status for {} out of {}", currentCount, totalCount);
MessageToSend finalUpdateMessage = getStatusMessageToSend(totalCount, channel.getGuild().getIdLong(), currentCount);
interactionService.editOriginal(finalUpdateMessage, interactionHook);
};
}
@Override @Override
public CompletableFuture<Void> purgeMessagesInChannel(Integer count, GuildMessageChannel channel, Message origin, Member purgingRestriction) { public CompletableFuture<Void> purgeMessagesInChannel(Integer count, GuildMessageChannel channel, Message origin, Member purgingRestriction) {
return purgeMessagesInChannel(count, channel, origin.getIdLong(), purgingRestriction); return purgeMessagesInChannel(count, channel, origin.getIdLong(), purgingRestriction);
} }
@Override
public CompletionStage<Void> purgeMessagesInChannel(Integer amountOfMessages, GuildMessageChannel guildMessageChannel, Long startId, InteractionHook hook, Member memberToPurgeMessagesOf) {
return purgeMessages(amountOfMessages, guildMessageChannel, startId, memberToPurgeMessagesOf, amountOfMessages, 0, hook);
}
private CompletableFuture<Void> purgeMessages(Integer amountToDelete, GuildMessageChannel channel, Long startId, Member purgedMember, Integer totalCount, Integer currentCount, InteractionHook interactionHook) {
int toDeleteInThisIteration;
if(amountToDelete >= PURGE_MAX_MESSAGES){
toDeleteInThisIteration = PURGE_MAX_MESSAGES;
} else {
toDeleteInThisIteration = amountToDelete % PURGE_MAX_MESSAGES;
}
metricService.incrementCounter(PURGE_MESSAGE_COUNTER_METRIC, (long) toDeleteInThisIteration);
log.info("Purging {} this iteration ({}/{}) messages in channel {} in server {}.", toDeleteInThisIteration, currentCount, totalCount, channel.getId(), channel.getGuild().getId());
CompletableFuture<MessageHistory> historyFuture = channelService.getHistoryOfChannel(channel, startId, toDeleteInThisIteration);
MessageToSend statusMessageToSend = getStatusMessageToSend(totalCount, channel.getGuild().getIdLong(), 0);
CompletableFuture<Message> statusMessageFuture = interactionService.editOriginal(statusMessageToSend, interactionHook);
CompletableFuture<Void> deletionFuture = new CompletableFuture<>();
CompletableFuture<Void> retrievalFuture = CompletableFuture.allOf(historyFuture, statusMessageFuture);
retrievalFuture.thenAccept(voidParam -> {
try {
List<Message> retrievedHistory = historyFuture.get().getRetrievedHistory();
List<Message> messagesToDeleteNow = filterMessagesToDelete(retrievedHistory, purgedMember);
if(messagesToDeleteNow.isEmpty()) {
log.warn("No messages found to delete, all were filtered.");
deletionFuture.completeExceptionally(new NoMessageFoundException());
return;
}
Message latestMessage = messagesToDeleteNow.get(messagesToDeleteNow.size() - 1);
log.debug("Deleting {} messages directly", messagesToDeleteNow.size());
int newCurrentCount = currentCount + messagesToDeleteNow.size();
int newAmountToDelete = amountToDelete - PURGE_MAX_MESSAGES;
Consumer<Void> consumer = deletionConsumer(newAmountToDelete, channel, purgedMember, totalCount, newCurrentCount, deletionFuture, interactionHook, latestMessage);
if (messagesToDeleteNow.size() > 1) {
bulkDeleteMessages(channel, deletionFuture, messagesToDeleteNow, consumer);
} else if (messagesToDeleteNow.size() == 1) {
messageService.deleteMessageWithAction(latestMessage).queue(consumer, deletionFuture::completeExceptionally);
}
} catch (Exception e) {
log.warn("Failed to purge messages.", e);
deletionFuture.completeExceptionally(e);
}
}).exceptionally(throwable -> {
log.warn("Failed to fetch messages.", throwable);
return null;
});
return CompletableFuture.allOf(retrievalFuture, deletionFuture);
}
@PostConstruct @PostConstruct
public void postConstruct() { public void postConstruct() {
metricService.registerCounter(PURGE_MESSAGE_COUNTER_METRIC, "Amount of messages deleted by purge."); metricService.registerCounter(PURGE_MESSAGE_COUNTER_METRIC, "Amount of messages deleted by purge.");

View File

@@ -11,6 +11,7 @@ import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementServ
import dev.sheldan.abstracto.core.service.management.ServerManagementService; import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.utils.SnowflakeUtils;
import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition; import dev.sheldan.abstracto.moderation.config.feature.ModerationFeatureDefinition;
import dev.sheldan.abstracto.moderation.config.feature.WarningDecayFeatureConfig; import dev.sheldan.abstracto.moderation.config.feature.WarningDecayFeatureConfig;
import dev.sheldan.abstracto.moderation.config.feature.WarningFeatureConfig; import dev.sheldan.abstracto.moderation.config.feature.WarningFeatureConfig;
@@ -167,7 +168,17 @@ public class WarnServiceBean implements WarnService {
} }
ServerUser warnedServerUser = ServerUser.fromAUserInAServer(warnedUser); ServerUser warnedServerUser = ServerUser.fromAUserInAServer(warnedUser);
ServerUser warningServerUser = ServerUser.fromAUserInAServer(warnedUser); ServerUser warningServerUser = ServerUser.fromAUserInAServer(warnedUser);
ServerChannelMessage commandMessage = ServerChannelMessage.fromMessage(context.getMessage()); ServerChannelMessage commandMessage;
if(context.getMessage() != null) {
commandMessage = ServerChannelMessage.fromMessage(context.getMessage());
} else {
commandMessage = ServerChannelMessage
.builder()
.serverId(context.getGuild().getIdLong())
.channelId(context.getChannel().getIdLong())
.messageId(SnowflakeUtils.createSnowFlake())
.build();
}
warningCreatedListenerManager.sendWarningCreatedEvent(createdWarning.getWarnId(), warnedServerUser, warningServerUser, context.getReason(), commandMessage); warningCreatedListenerManager.sendWarningCreatedEvent(createdWarning.getWarnId(), warnedServerUser, warningServerUser, context.getReason(), commandMessage);
} }

View File

@@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.CounterService; import dev.sheldan.abstracto.core.service.CounterService;
import dev.sheldan.abstracto.moderation.exception.UserNoteNotFoundException;
import dev.sheldan.abstracto.moderation.model.database.UserNote; import dev.sheldan.abstracto.moderation.model.database.UserNote;
import dev.sheldan.abstracto.moderation.repository.UserNoteRepository; import dev.sheldan.abstracto.moderation.repository.UserNoteRepository;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -45,9 +46,15 @@ public class UserNoteManagementServiceBean implements UserNoteManagementService
userNoteRepository.deleteByUserNoteId_IdAndUserNoteId_ServerId(id, server.getId()); userNoteRepository.deleteByUserNoteId_IdAndUserNoteId_ServerId(id, server.getId());
} }
@Override
public void deleteNote(UserNote userNote) {
log.info("Deleting user note directly with id {} in server {}.", userNote.getUserNoteId().getId(), userNote.getServer().getId());
userNoteRepository.delete(userNote);
}
@Override @Override
public UserNote loadNote(Long serverId, Long userNoteId) { public UserNote loadNote(Long serverId, Long userNoteId) {
return userNoteRepository.findByUserNoteId_IdAndUserNoteId_ServerId(userNoteId, serverId); return userNoteRepository.findByUserNoteId_IdAndUserNoteId_ServerId(userNoteId, serverId).orElseThrow(UserNoteNotFoundException::new);
} }
@Override @Override

View File

@@ -1,9 +1,9 @@
package dev.sheldan.abstracto.moderation.service.management; package dev.sheldan.abstracto.moderation.service.management;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.ServerSpecificId; import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.moderation.exception.WarnNotFoundException;
import dev.sheldan.abstracto.moderation.model.database.Warning; import dev.sheldan.abstracto.moderation.model.database.Warning;
import dev.sheldan.abstracto.moderation.repository.WarnRepository; import dev.sheldan.abstracto.moderation.repository.WarnRepository;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -86,7 +86,7 @@ public class WarnManagementServiceBean implements WarnManagementService {
@Override @Override
public Warning findById(Long id, Long serverId) { public Warning findById(Long id, Long serverId) {
return findByIdOptional(id, serverId).orElseThrow(() -> new AbstractoRunTimeException("Warning not found.")); return findByIdOptional(id, serverId).orElseThrow(WarnNotFoundException::new);
} }
@Override @Override

View File

@@ -1,54 +0,0 @@
package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.moderation.service.BanService;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class BanTest {
@InjectMocks
private Ban testUnit;
@Mock
private BanService banService;
@Captor
private ArgumentCaptor<Member> banLogModelCaptor;
@Mock
private User bannedMember;
@Test
public void testBanWithReason() {
String customReason = "reason2";
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(bannedMember, customReason));
when(banService.banUserWithNotification(eq(bannedMember), eq(customReason), banLogModelCaptor.capture(), eq(0), any(Message.class))).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);
Member banningMember = banLogModelCaptor.getValue();
Assert.assertEquals(parameters.getAuthor(), banningMember);
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,72 +0,0 @@
package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ResultState;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.moderation.service.management.UserNoteManagementService;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class DeleteNoteTest {
@InjectMocks
private DeleteNote testUnit;
@Mock
private UserNoteManagementService userNoteManagementService;
@Mock
private TemplateService templateService;
@Mock
private ServerManagementService serverManagementService;
private static final Long NOTE_ID = 5L;
private static final Long SERVER_ID = 4L;
@Test
public void testDeleteExistingNote() {
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(NOTE_ID));
AServer server = Mockito.mock(AServer.class);
when(serverManagementService.loadServer(parameters.getGuild())).thenReturn(server);
when(userNoteManagementService.noteExists(NOTE_ID, server)).thenReturn(true);
CommandResult result = testUnit.execute(parameters);
CommandTestUtilities.checkSuccessfulCompletion(result);
verify(userNoteManagementService, times(1)).deleteNote(NOTE_ID, server);
}
@Test
public void testDeleteNotExistingNote() {
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(NOTE_ID));
AServer server = Mockito.mock(AServer.class);
when(parameters.getGuild().getIdLong()).thenReturn(SERVER_ID);
when(serverManagementService.loadServer(parameters.getGuild())).thenReturn(server);
when(userNoteManagementService.noteExists(NOTE_ID, server)).thenReturn(false);
when(templateService.renderSimpleTemplate(DeleteNote.NOTE_NOT_FOUND_EXCEPTION_TEMPLATE, SERVER_ID)).thenReturn("error");
CommandResult result = testUnit.execute(parameters);
Assert.assertEquals(ResultState.ERROR, result.getResult());
Assert.assertNotNull(result.getMessage());
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,54 +0,0 @@
package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.moderation.model.database.Warning;
import dev.sheldan.abstracto.moderation.service.management.WarnManagementService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.Optional;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class DeleteWarningTest {
@InjectMocks
private DeleteWarning testUnit;
@Mock
private WarnManagementService warnManagementService;
private static final Long WARN_ID = 5L;
private static final Long SERVER_ID = 1L;
@Test
public void testDeleteExistingWarning() {
Warning existingWarning = Mockito.mock(Warning.class);
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(WARN_ID));
when(parameters.getGuild().getIdLong()).thenReturn(SERVER_ID);
when(warnManagementService.findByIdOptional(WARN_ID, SERVER_ID)).thenReturn(Optional.of(existingWarning));
CommandResult result = testUnit.execute(parameters);
verify(warnManagementService, times(1)).deleteWarning(existingWarning);
CommandTestUtilities.checkSuccessfulCompletion(result);
}
@Test
public void testDeleteNotExistingWarning() {
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(WARN_ID));
CommandResult result = testUnit.execute(parameters);
CommandTestUtilities.checkSuccessfulCompletion(result);
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,60 +0,0 @@
package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.service.PostTargetService;
import dev.sheldan.abstracto.moderation.config.posttarget.ModerationPostTarget;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class BanServiceBeanTest {
public static final String REASON = "reason";
private static final Long SERVER_ID = 4L;
private static final Long USER_ID = 5L;
@InjectMocks
private BanServiceBean testUnit;
@Mock
private TemplateService templateService;
@Mock
private PostTargetService postTargetService;
@Mock
private Message message;
@Test
public void testBanMemberWithLog() {
Member memberToBan = Mockito.mock(Member.class);
User user = Mockito.mock(User.class);
when(memberToBan.getUser()).thenReturn(user);
Member banningMember = Mockito.mock(Member.class);
Guild mockedGuild = Mockito.mock(Guild.class);
when(memberToBan.getGuild()).thenReturn(mockedGuild);
when(mockedGuild.getIdLong()).thenReturn(SERVER_ID);
AuditableRestAction mockedAction = mock(AuditableRestAction.class);
when(mockedAction.submit()).thenReturn(CompletableFuture.completedFuture(null));
when(mockedGuild.ban(user, 0, REASON)).thenReturn(mockedAction);
MessageToSend mockedMessage = Mockito.mock(MessageToSend.class);
when(templateService.renderEmbedTemplate(eq(BanServiceBean.BAN_LOG_TEMPLATE), any(), eq(SERVER_ID))).thenReturn(mockedMessage);
testUnit.banMemberWithNotification(memberToBan, REASON, banningMember, 0, message);
verify(mockedGuild, times(1)).ban(user, 0, REASON);
verify(postTargetService, times(1)).sendEmbedInPostTarget(mockedMessage, ModerationPostTarget.BAN_LOG, SERVER_ID);
}
}

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.moderation.config;
public class ModerationSlashCommandNames {
public static final String MODERATION = "moderation";
public static final String WARNINGS = "warnings";
public static final String USER_NOTES = "usernotes";
public static final String MUTE = "mute";
public static final String WARN_DECAY = "warningdecay";
public static final String WARNINGS_PUBLIC = "warningspublic";
}

View File

@@ -10,7 +10,6 @@ public enum ModerationFeatureDefinition implements FeatureDefinition {
MUTING("muting"), MUTING("muting"),
AUTOMATIC_WARN_DECAY("warnDecay"), AUTOMATIC_WARN_DECAY("warnDecay"),
USER_NOTES("userNotes"), USER_NOTES("userNotes"),
INVITE_FILTER("inviteFilter"),
REPORT_REACTIONS("reportReactions"), REPORT_REACTIONS("reportReactions"),
INFRACTIONS("infractions") INFRACTIONS("infractions")
; ;

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.moderation.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class UserNoteNotFoundException extends AbstractoTemplatableException {
@Override
public String getTemplateName() {
return "user_note_not_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.moderation.exception;
import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException;
public class WarnNotFoundException extends AbstractoTemplatableException {
@Override
public String getTemplateName() {
return "warn_not_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.moderation.model;
public enum BanResult {
NOTIFICATION_FAILED, SUCCESSFUL
}

View File

@@ -1,18 +1,19 @@
package dev.sheldan.abstracto.moderation.model.template.command; package dev.sheldan.abstracto.moderation.model.template.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.GuildMessageChannel;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
/** /**
* Used when rendering the notification when a member was kicked. The template is: "kick_log_embed" * Used when rendering the notification when a member was kicked. The template is: "kick_log_embed"
*/ */
@Getter @Getter
@SuperBuilder @Builder
@Setter @Setter
public class KickLogModel extends SlimUserInitiatedServerContext { public class KickLogModel {
/** /**
* The reason of the kick * The reason of the kick
*/ */
@@ -21,4 +22,7 @@ public class KickLogModel extends SlimUserInitiatedServerContext {
* The member being kicked * The member being kicked
*/ */
private Member kickedUser; private Member kickedUser;
private Member member;
private Guild guild;
private GuildMessageChannel channel;
} }

View File

@@ -1,17 +1,18 @@
package dev.sheldan.abstracto.moderation.model.template.command; package dev.sheldan.abstracto.moderation.model.template.command;
import dev.sheldan.abstracto.core.models.FullUserInServer; import dev.sheldan.abstracto.core.models.FullUserInServer;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder; import net.dv8tion.jda.api.entities.Member;
import java.util.List; import java.util.List;
@SuperBuilder @Builder
@Getter @Getter
@Setter @Setter
public class ListNotesModel extends UserInitiatedServerContext { public class ListNotesModel {
private List<NoteEntryModel> userNotes; private List<NoteEntryModel> userNotes;
private FullUserInServer specifiedUser; private FullUserInServer specifiedUser;
private Member member;
} }

View File

@@ -1,15 +1,14 @@
package dev.sheldan.abstracto.moderation.model.template.command; package dev.sheldan.abstracto.moderation.model.template.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder;
import java.util.List; import java.util.List;
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class MutesModel extends SlimUserInitiatedServerContext { public class MutesModel {
private List<MuteEntry> mutes; private List<MuteEntry> mutes;
} }

View File

@@ -1,17 +1,17 @@
package dev.sheldan.abstracto.moderation.model.template.command; package dev.sheldan.abstracto.moderation.model.template.command;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder; import net.dv8tion.jda.api.entities.Member;
/** /**
* Used to render the response of the myWarnings command. The template is: 'myWarnings_response_embed' * Used to render the response of the myWarnings command. The template is: 'myWarnings_response_embed'
*/ */
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class MyWarningsModel extends UserInitiatedServerContext { public class MyWarningsModel {
/** /**
* The total amount of warnings the member has * The total amount of warnings the member has
*/ */
@@ -20,4 +20,5 @@ public class MyWarningsModel extends UserInitiatedServerContext {
* The current (only active) amount of warnings the member has * The current (only active) amount of warnings the member has
*/ */
private Long currentWarnCount; private Long currentWarnCount;
private Member member;
} }

View File

@@ -1,19 +1,21 @@
package dev.sheldan.abstracto.moderation.model.template.command; package dev.sheldan.abstracto.moderation.model.template.command;
import dev.sheldan.abstracto.core.models.context.SlimUserInitiatedServerContext;
import dev.sheldan.abstracto.moderation.model.database.Warning; import dev.sheldan.abstracto.moderation.model.database.Warning;
import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.GuildMessageChannel;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
/** /**
* Used when rendering the notification when a member was warned. The template is: "warn_log_embed" * Used when rendering the notification when a member was warned. The template is: "warn_log_embed"
*/ */
@Getter @Getter
@SuperBuilder @Builder
@Setter @Setter
public class WarnContext extends SlimUserInitiatedServerContext { public class WarnContext {
/** /**
* The reason why the warn was cast * The reason why the warn was cast
*/ */
@@ -27,4 +29,8 @@ public class WarnContext extends SlimUserInitiatedServerContext {
*/ */
private Long warnId; private Long warnId;
private Long infractionId; private Long infractionId;
private Member member;
private Guild guild;
private Message message;
private GuildMessageChannel channel;
} }

View File

@@ -1,17 +1,14 @@
package dev.sheldan.abstracto.moderation.service; package dev.sheldan.abstracto.moderation.service;
import net.dv8tion.jda.api.entities.Guild; import dev.sheldan.abstracto.moderation.model.BanResult;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.User;
import java.time.Duration; import java.time.Duration;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public interface BanService { public interface BanService {
String BAN_EFFECT_KEY = "ban"; String BAN_EFFECT_KEY = "ban";
CompletableFuture<Void> banMemberWithNotification(Member member, String reason, Member banningMember, Integer deletionDays, Message message); CompletableFuture<BanResult> banUserWithNotification(User user, String reason, Member banningMember, Integer deletionDays);
CompletableFuture<Void> banUserWithNotification(User user, String reason, Member banningMember, Integer deletionDays, Message message);
CompletableFuture<Void> unBanUserWithNotification(User user, Member unBanningUser); CompletableFuture<Void> unBanUserWithNotification(User user, Member unBanningUser);
CompletableFuture<Void> banUser(Guild guild, User user, Integer deletionDays, String reason); CompletableFuture<Void> banUser(Guild guild, User user, Integer deletionDays, String reason);
CompletableFuture<Void> unbanUser(Guild guild, User user); CompletableFuture<Void> unbanUser(Guild guild, User user);

View File

@@ -1,10 +1,13 @@
package dev.sheldan.abstracto.moderation.service; package dev.sheldan.abstracto.moderation.service;
import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.interactions.InteractionHook;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
public interface PurgeService { public interface PurgeService {
CompletableFuture<Void> purgeMessagesInChannel(Integer count, GuildMessageChannel channel, Long messageId, Member purgingRestriction); CompletableFuture<Void> purgeMessagesInChannel(Integer count, GuildMessageChannel channel, Long messageId, Member purgingRestriction);
CompletableFuture<Void> purgeMessagesInChannel(Integer count, GuildMessageChannel channel, Message origin, Member purgingRestriction); CompletableFuture<Void> purgeMessagesInChannel(Integer count, GuildMessageChannel channel, Message origin, Member purgingRestriction);
CompletionStage<Void> purgeMessagesInChannel(Integer amountOfMessages, GuildMessageChannel guildMessageChannel, Long startId, InteractionHook hook, Member memberToPurgeMessagesOf);
} }

View File

@@ -9,6 +9,7 @@ import java.util.List;
public interface UserNoteManagementService { public interface UserNoteManagementService {
UserNote createUserNote(AUserInAServer aUserInAServer, String note); UserNote createUserNote(AUserInAServer aUserInAServer, String note);
void deleteNote(Long id, AServer server); void deleteNote(Long id, AServer server);
void deleteNote(UserNote userNote);
UserNote loadNote(Long serverId, Long userNoteId); UserNote loadNote(Long serverId, Long userNoteId);
boolean noteExists(Long id, AServer server); boolean noteExists(Long id, AServer server);
List<UserNote> loadNotesForUser(AUserInAServer aUserInAServer); List<UserNote> loadNotesForUser(AUserInAServer aUserInAServer);

View File

@@ -5,22 +5,29 @@ import dev.sheldan.abstracto.core.command.condition.CommandCondition;
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition; import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
import dev.sheldan.abstracto.modmail.model.ClosingContext; import dev.sheldan.abstracto.modmail.model.ClosingContext;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread; import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.service.ModMailThreadService; import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -34,7 +41,12 @@ import java.util.concurrent.CompletableFuture;
@Slf4j @Slf4j
public class Close extends AbstractConditionableCommand { public class Close extends AbstractConditionableCommand {
public static final String MODMAIL_CLOSE_DEFAULT_NOTE_TEMPLATE_KEY = "modmail_close_default_note"; private static final String MODMAIL_CLOSE_DEFAULT_NOTE_TEMPLATE_KEY = "modmail_close_default_note";
private static final String CLOSE_COMMAND = "close";
private static final String NOTE_PARAMETER = "note";
private static final String SILENTLY_PARAMETER = "silently";
private static final String LOG_PARAMETER = "log";
private static final String CLOSE_RESPONSE = "close_response";
@Autowired @Autowired
private ModMailContextCondition requiresModMailCondition; private ModMailContextCondition requiresModMailCondition;
@@ -50,6 +62,15 @@ public class Close extends AbstractConditionableCommand {
@Autowired @Autowired
private ChannelManagementService channelManagementService; private ChannelManagementService channelManagementService;
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private Close self;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
@@ -61,6 +82,7 @@ public class Close extends AbstractConditionableCommand {
.builder() .builder()
.closingMember(commandContext.getAuthor()) .closingMember(commandContext.getAuthor())
.notifyUser(true) .notifyUser(true)
.channel(commandContext.getChannel())
.log(true) .log(true)
.note(note) .note(note)
.build(); .build();
@@ -68,16 +90,96 @@ public class Close extends AbstractConditionableCommand {
.thenApply(aVoid -> CommandResult.fromIgnored()); .thenApply(aVoid -> CommandResult.fromIgnored());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String note;
if(slashCommandParameterService.hasCommandOption(NOTE_PARAMETER, event)) {
note = slashCommandParameterService.getCommandOption(NOTE_PARAMETER, event, String.class);
} else {
note = templateService.renderTemplate(MODMAIL_CLOSE_DEFAULT_NOTE_TEMPLATE_KEY, new Object(), event.getGuild().getIdLong());
}
Boolean silently;
if(slashCommandParameterService.hasCommandOption(SILENTLY_PARAMETER, event)) {
silently = slashCommandParameterService.getCommandOption(SILENTLY_PARAMETER, event, Boolean.class);
} else {
silently = false;
}
Boolean log;
if(slashCommandParameterService.hasCommandOption(LOG_PARAMETER, event)) {
log = slashCommandParameterService.getCommandOption(LOG_PARAMETER, event, Boolean.class);
} else {
log = false;
}
ClosingContext context = ClosingContext
.builder()
.closingMember(event.getMember())
.channel(event.getChannel())
.notifyUser(!silently)
.log(log)
.note(note)
.build();
return interactionService.replyEmbed(CLOSE_RESPONSE, event)
.thenCompose(interactionHook -> self.closeThread(context))
.thenApply(aVoid -> CommandResult.fromIgnored());
}
@Transactional
public CompletableFuture<Void> closeThread(ClosingContext closingContext) {
AChannel channel = channelManagementService.loadChannel(closingContext.getChannel());
ModMailThread thread = modMailThreadManagementService.getByChannel(channel);
return modMailThreadService.closeModMailThread(thread, closingContext, new ArrayList<>());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
Parameter note = Parameter.builder().name("note").type(String.class).remainder(true).optional(true).templated(true).build(); Parameter noteParameter = Parameter
List<Parameter> parameters = Arrays.asList(note); .builder()
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .name(NOTE_PARAMETER)
.type(String.class)
.remainder(true)
.optional(true)
.templated(true)
.build();
Parameter silentlyParameter = Parameter
.builder()
.name(SILENTLY_PARAMETER)
.type(Boolean.class)
.remainder(true)
.slashCommandOnly(true)
.optional(true)
.templated(true)
.build();
Parameter logParameter = Parameter
.builder()
.name(LOG_PARAMETER)
.type(Boolean.class)
.remainder(true)
.slashCommandOnly(true)
.optional(true)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(noteParameter, silentlyParameter, logParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
.commandName(CLOSE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("close") .name(CLOSE_COMMAND)
.module(ModMailModuleDefinition.MODMAIL) .module(ModMailModuleDefinition.MODMAIL)
.parameters(parameters) .parameters(parameters)
.help(helpInfo) .help(helpInfo)
.slashCommandConfig(slashCommandConfig)
.async(true) .async(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.templated(true) .templated(true)

View File

@@ -4,16 +4,19 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException; import dev.sheldan.abstracto.core.exception.EntityGuildMismatchException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition; import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread; import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.model.template.ModMailThreadExistsModel; import dev.sheldan.abstracto.modmail.model.template.ModMailThreadExistsModel;
import dev.sheldan.abstracto.modmail.service.ModMailThreadService; import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
@@ -21,9 +24,13 @@ import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementS
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.interactions.InteractionHook;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -36,6 +43,11 @@ import java.util.concurrent.CompletableFuture;
@Slf4j @Slf4j
public class Contact extends AbstractConditionableCommand { public class Contact extends AbstractConditionableCommand {
private static final String CONTACT_PARAMETER = "contact";
private static final String USER_PARMETER = "user";
private static final String MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE = "modmail_thread_already_exists";
private static final String CONTACT_RESPONSE = "contact_response";
@Autowired @Autowired
private ModMailThreadService modMailThreadService; private ModMailThreadService modMailThreadService;
@@ -48,6 +60,12 @@ public class Contact extends AbstractConditionableCommand {
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
Member targetUser = (Member) commandContext.getParameters().getParameters().get(0); Member targetUser = (Member) commandContext.getParameters().getParameters().get(0);
@@ -59,26 +77,73 @@ public class Contact extends AbstractConditionableCommand {
// containing a link to the channel, instead of opening a new one // containing a link to the channel, instead of opening a new one
if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) { if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) {
log.info("Modmail thread for user {} in server {} already exists. Notifying user {}.", commandContext.getAuthor().getId(), commandContext.getGuild().getId(), user.getUserReference().getId()); log.info("Modmail thread for user {} in server {} already exists. Notifying user {}.", commandContext.getAuthor().getId(), commandContext.getGuild().getId(), user.getUserReference().getId());
ModMailThreadExistsModel model = (ModMailThreadExistsModel) ContextConverter.fromCommandContext(commandContext, ModMailThreadExistsModel.class);
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user); ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
model.setExistingModMailThread(existingThread); ModMailThreadExistsModel model = ModMailThreadExistsModel
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInTextChannelList("modmail_thread_already_exists", model, commandContext.getChannel()); .builder()
.existingModMailThread(existingThread)
.build();
List<CompletableFuture<Message>> futures = channelService.sendEmbedTemplateInTextChannelList(MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE, model, commandContext.getChannel());
return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored()); return FutureUtils.toSingleFutureGeneric(futures).thenApply(aVoid -> CommandResult.fromIgnored());
} else { } else {
return modMailThreadService.createModMailThreadForUser(targetUser, null, commandContext.getChannel(), false, commandContext.getUndoActions()) return modMailThreadService.createModMailThreadForUser(targetUser, null, false, commandContext.getUndoActions())
.thenCompose(unused -> modMailThreadService.sendContactNotification(targetUser, unused, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Member member = slashCommandParameterService.getCommandOption(USER_PARMETER, event, Member.class);
if(!member.getGuild().equals(event.getGuild())) {
throw new EntityGuildMismatchException();
}
AUserInAServer user = userManagementService.loadOrCreateUser(member);
// if this AUserInAServer already has an open thread, we should instead post a message
// containing a link to the channel, instead of opening a new one
if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) {
log.info("Modmail thread for user {} in server {} already exists. Notifying user {}.", event.getMember().getId(), event.getGuild().getId(), user.getUserReference().getId());
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
ModMailThreadExistsModel model = ModMailThreadExistsModel
.builder()
.existingModMailThread(existingThread)
.build();
return interactionService.replyEmbed(MODMAIL_THREAD_ALREADY_EXISTS_TEMPLATE, model, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
} else {
CompletableFuture<InteractionHook> response = interactionService.replyEmbed(CONTACT_RESPONSE, event);
CompletableFuture<MessageChannel> threadFuture = modMailThreadService.createModMailThreadForUser(member, null, false, new ArrayList<>());
return CompletableFuture.allOf(response, threadFuture)
.thenCompose(unused -> modMailThreadService.sendContactNotification(member, threadFuture.join(), response.join()))
.thenApply(o -> CommandResult.fromSuccess());
}
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
Parameter responseText = Parameter.builder().name("user").type(Member.class).templated(true).build(); Parameter responseText = Parameter
.builder()
.name(USER_PARMETER)
.type(Member.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(responseText); List<Parameter> parameters = Arrays.asList(responseText);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
.commandName(CONTACT_PARAMETER)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("contact") .name(CONTACT_PARAMETER)
.module(ModMailModuleDefinition.MODMAIL) .module(ModMailModuleDefinition.MODMAIL)
.parameters(parameters) .parameters(parameters)
.slashCommandConfig(slashCommandConfig)
.async(true) .async(true)
.help(helpInfo) .help(helpInfo)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -4,19 +4,24 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
import dev.sheldan.abstracto.core.command.condition.CommandCondition; import dev.sheldan.abstracto.core.command.condition.CommandCondition;
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.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition; import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread; import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService; import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
/** /**
@@ -26,6 +31,9 @@ import java.util.List;
@Component @Component
public class Subscribe extends AbstractConditionableCommand { public class Subscribe extends AbstractConditionableCommand {
private static final String SUBSCRIBE_COMMAND = "subscribe";
private static final String SUBSCRIBE_RESPONSE = "subscribe_response";
@Autowired @Autowired
private ModMailContextCondition requiresModMailCondition; private ModMailContextCondition requiresModMailCondition;
@@ -38,6 +46,9 @@ public class Subscribe extends AbstractConditionableCommand {
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(commandContext.getChannel().getIdLong()); ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(commandContext.getChannel().getIdLong());
@@ -45,11 +56,31 @@ public class Subscribe extends AbstractConditionableCommand {
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(event.getChannel().getIdLong());
modMailSubscriptionService.subscribeToThread(userInServerManagementService.loadOrCreateUser(event.getMember()), modMailThread);
return interactionService.replyEmbed(SUBSCRIBE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
.commandName(SUBSCRIBE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("subscribe") .name(SUBSCRIBE_COMMAND)
.slashCommandConfig(slashCommandConfig)
.module(ModMailModuleDefinition.MODMAIL) .module(ModMailModuleDefinition.MODMAIL)
.help(helpInfo) .help(helpInfo)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -4,20 +4,25 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
import dev.sheldan.abstracto.core.command.condition.CommandCondition; import dev.sheldan.abstracto.core.command.condition.CommandCondition;
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.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition; import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition; import dev.sheldan.abstracto.modmail.config.ModMailFeatureDefinition;
import dev.sheldan.abstracto.modmail.config.ModMailSlashCommandNames;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread; import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService; import dev.sheldan.abstracto.modmail.service.ModMailSubscriptionService;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
/** /**
@@ -27,6 +32,9 @@ import java.util.List;
@Component @Component
public class UnSubscribe extends AbstractConditionableCommand { public class UnSubscribe extends AbstractConditionableCommand {
private static final String UN_SUBSCRIBE_COMMAND = "unSubscribe";
private static final String UN_SUBSCRIBE_RESPONSE = "unSubscribe_response";
@Autowired @Autowired
private ModMailContextCondition requiresModMailCondition; private ModMailContextCondition requiresModMailCondition;
@@ -39,6 +47,9 @@ public class UnSubscribe extends AbstractConditionableCommand {
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(commandContext.getChannel().getIdLong()); ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(commandContext.getChannel().getIdLong());
@@ -47,11 +58,32 @@ public class UnSubscribe extends AbstractConditionableCommand {
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
ModMailThread modMailThread = modMailThreadManagementService.getByChannelId(event.getChannel().getIdLong());
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(event.getMember());
modMailSubscriptionService.unsubscribeFromThread(aUserInAServer, modMailThread);
return interactionService.replyEmbed(UN_SUBSCRIBE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(ModMailSlashCommandNames.MODMAIL)
.commandName(UN_SUBSCRIBE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("unSubscribe") .name(UN_SUBSCRIBE_COMMAND)
.slashCommandConfig(slashCommandConfig)
.module(ModMailModuleDefinition.MODMAIL) .module(ModMailModuleDefinition.MODMAIL)
.help(helpInfo) .help(helpInfo)
.supportsEmbedException(true) .supportsEmbedException(true)

View File

@@ -8,7 +8,7 @@ import dev.sheldan.abstracto.modmail.condition.ModMailContextCondition;
import dev.sheldan.abstracto.modmail.condition.detail.NotInModMailThreadConditionDetail; import dev.sheldan.abstracto.modmail.condition.detail.NotInModMailThreadConditionDetail;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread; import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import dev.sheldan.abstracto.core.templating.service.TemplateService; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -24,9 +24,6 @@ public class RequiresModMailCondition implements ModMailContextCondition {
@Autowired @Autowired
private ModMailThreadManagementService modMailThreadManagementService; private ModMailThreadManagementService modMailThreadManagementService;
@Autowired
private TemplateService templateService;
@Autowired @Autowired
private ChannelManagementService channelManagementService; private ChannelManagementService channelManagementService;
@@ -34,8 +31,36 @@ public class RequiresModMailCondition implements ModMailContextCondition {
public ConditionResult shouldExecute(CommandContext commandContext, Command command) { public ConditionResult shouldExecute(CommandContext commandContext, Command command) {
Optional<ModMailThread> threadOptional = modMailThreadManagementService.getByChannelOptional(channelManagementService.loadChannel(commandContext.getChannel())); Optional<ModMailThread> threadOptional = modMailThreadManagementService.getByChannelOptional(channelManagementService.loadChannel(commandContext.getChannel()));
if(threadOptional.isPresent()) { if(threadOptional.isPresent()) {
return ConditionResult.builder().result(true).build(); return ConditionResult
.builder()
.result(true)
.build();
} }
return ConditionResult.builder().result(false).conditionDetail(new NotInModMailThreadConditionDetail()).build(); return ConditionResult
.builder()
.result(false)
.conditionDetail(new NotInModMailThreadConditionDetail())
.build();
}
@Override
public ConditionResult shouldExecute(SlashCommandInteractionEvent slashCommandInteractionEvent, Command command) {
Optional<ModMailThread> threadOptional = modMailThreadManagementService.getByChannelOptional(channelManagementService.loadChannel(slashCommandInteractionEvent.getChannel()));
if(threadOptional.isPresent()) {
return ConditionResult
.builder()
.result(true)
.build();
}
return ConditionResult
.builder()
.result(false)
.conditionDetail(new NotInModMailThreadConditionDetail())
.build();
}
@Override
public boolean supportsSlashCommands() {
return true;
} }
} }

View File

@@ -33,9 +33,6 @@ public class ModMailInitialButtonListener implements ButtonClickedListener {
@Autowired @Autowired
private UndoActionService undoActionService; private UndoActionService undoActionService;
@Autowired
private MessageService messageService;
@Autowired @Autowired
private ComponentPayloadManagementService componentPayloadService; private ComponentPayloadManagementService componentPayloadService;
@@ -58,7 +55,7 @@ public class ModMailInitialButtonListener implements ButtonClickedListener {
.thenCompose(member -> channelService.retrieveMessageInChannel(model.getEvent().getChannel(), choices.getMessageId()) .thenCompose(member -> channelService.retrieveMessageInChannel(model.getEvent().getChannel(), choices.getMessageId())
.thenCompose(originalMessage -> { .thenCompose(originalMessage -> {
try { try {
return modMailThreadService.createModMailThreadForUser(member, originalMessage, model.getEvent().getChannel(), true, undoActions); return modMailThreadService.createModMailThreadForUser(member, originalMessage, true, undoActions);
} catch (Exception ex) { } catch (Exception ex) {
log.error("Failed to setup thread correctly", ex); log.error("Failed to setup thread correctly", ex);
undoActionService.performActions(undoActions); undoActionService.performActions(undoActions);

View File

@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.modmail.service;
import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException; import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.metric.service.CounterMetric; import dev.sheldan.abstracto.core.metric.service.CounterMetric;
import dev.sheldan.abstracto.core.metric.service.MetricService; import dev.sheldan.abstracto.core.metric.service.MetricService;
import dev.sheldan.abstracto.core.metric.service.MetricTag; import dev.sheldan.abstracto.core.metric.service.MetricTag;
@@ -39,6 +40,7 @@ import dev.sheldan.abstracto.core.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException; import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.interactions.InteractionHook;
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -149,6 +151,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Autowired @Autowired
private ComponentPayloadService componentPayloadService; private ComponentPayloadService componentPayloadService;
@Autowired
private InteractionService interactionService;
public static final String MODMAIL_THREAD_METRIC = "modmail.threads"; public static final String MODMAIL_THREAD_METRIC = "modmail.threads";
public static final String MODMAIL_MESSAGE_METRIC = "modmail.messges"; public static final String MODMAIL_MESSAGE_METRIC = "modmail.messges";
public static final String ACTION = "action"; public static final String ACTION = "action";
@@ -180,7 +185,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
public static final String MODMAIL_INITIAL_ORIGIN = "modmailInitial"; public static final String MODMAIL_INITIAL_ORIGIN = "modmailInitial";
@Override @Override
public CompletableFuture<Void> createModMailThreadForUser(Member member, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated, List<UndoActionInstance> undoActions) { public CompletableFuture<MessageChannel> createModMailThreadForUser(Member member, Message initialMessage, boolean userInitiated, List<UndoActionInstance> undoActions) {
Long serverId = member.getGuild().getIdLong(); Long serverId = member.getGuild().getIdLong();
Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId); Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId);
AServer server = serverManagementService.loadServer(member.getGuild().getIdLong()); AServer server = serverManagementService.loadServer(member.getGuild().getIdLong());
@@ -199,20 +204,32 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
CompletableFuture<TextChannel> textChannelFuture = channelService.createTextChannel(channelName, server, categoryId); CompletableFuture<TextChannel> textChannelFuture = channelService.createTextChannel(channelName, server, categoryId);
return textChannelFuture.thenCompose(channel -> { return textChannelFuture.thenCompose(channel -> {
undoActions.add(UndoActionInstance.getChannelDeleteAction(serverId, channel.getIdLong())); undoActions.add(UndoActionInstance.getChannelDeleteAction(serverId, channel.getIdLong()));
return self.performModMailThreadSetup(member, initialMessage, channel, userInitiated, undoActions, feedBackChannel); return self.performModMailThreadSetup(member, initialMessage, channel, userInitiated, undoActions)
.thenCompose(unused -> CompletableFuture.completedFuture(channel));
}); });
} }
@Transactional @Transactional
public CompletableFuture<Void> sendContactNotification(Member member, TextChannel textChannel, MessageChannel feedBackChannel) { @Override
public CompletableFuture<Void> sendContactNotification(Member member, MessageChannel messageChannel, MessageChannel feedBackChannel) {
ContactNotificationModel model = ContactNotificationModel ContactNotificationModel model = ContactNotificationModel
.builder() .builder()
.createdChannel(textChannel) .createdChannel(messageChannel)
.targetMember(member) .targetMember(member)
.build(); .build();
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannelList(MODMAIL_THREAD_CREATED_TEMPLATE_KEY, model, feedBackChannel)); return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInMessageChannelList(MODMAIL_THREAD_CREATED_TEMPLATE_KEY, model, feedBackChannel));
} }
@Override
public CompletableFuture<Void> sendContactNotification(Member member, MessageChannel createdMessageChannel, InteractionHook interactionHook) {
ContactNotificationModel model = ContactNotificationModel
.builder()
.createdChannel(createdMessageChannel)
.targetMember(member)
.build();
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(MODMAIL_THREAD_CREATED_TEMPLATE_KEY, model, interactionHook));
}
/** /**
* This method is responsible for creating the instance in the database, sending the header in the newly created text channel and forwarding the initial message * This method is responsible for creating the instance in the database, sending the header in the newly created text channel and forwarding the initial message
* by the user (if any), after this is complete, this method executes the method to perform the mod mail notification. * by the user (if any), after this is complete, this method executes the method to perform the mod mail notification.
@@ -224,7 +241,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @return A {@link CompletableFuture future} which completes when the setup is done * @return A {@link CompletableFuture future} which completes when the setup is done
*/ */
@Transactional @Transactional
public CompletableFuture<Void> performModMailThreadSetup(Member member, Message initialMessage, TextChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions, MessageChannel feedBackChannel) { public CompletableFuture<Void> performModMailThreadSetup(Member member, Message initialMessage, TextChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions) {
log.info("Performing modmail thread setup for channel {} for user {} in server {}. It was initiated by a user: {}.", channel.getIdLong(), member.getId(), channel.getGuild().getId(), userInitiated); log.info("Performing modmail thread setup for channel {} for user {} in server {}. It was initiated by a user: {}.", channel.getIdLong(), member.getId(), channel.getGuild().getId(), userInitiated);
CompletableFuture<Void> headerFuture = sendModMailHeader(channel, member); CompletableFuture<Void> headerFuture = sendModMailHeader(channel, member);
CompletableFuture<Message> userReplyMessage; CompletableFuture<Message> userReplyMessage;
@@ -244,10 +261,6 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
return CompletableFuture.allOf(headerFuture, notificationFuture, userReplyMessage).thenAccept(aVoid -> { return CompletableFuture.allOf(headerFuture, notificationFuture, userReplyMessage).thenAccept(aVoid -> {
undoActions.clear(); undoActions.clear();
self.setupModMailThreadInDB(initialMessage, channel, member, userReplyMessage.join()); self.setupModMailThreadInDB(initialMessage, channel, member, userReplyMessage.join());
}).thenAccept(unused -> {
if(!userInitiated) {
self.sendContactNotification(member, channel, feedBackChannel);
}
}); });
} }
@@ -368,7 +381,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
log.info("Only one server available to modmail. Directly opening modmail thread for user {} in server {}.", initialMessage.getAuthor().getId(), chosenServerId); log.info("Only one server available to modmail. Directly opening modmail thread for user {} in server {}.", initialMessage.getAuthor().getId(), chosenServerId);
memberService.getMemberInServerAsync(chosenServerId, initialMessage.getAuthor().getIdLong()).thenCompose(member -> { memberService.getMemberInServerAsync(chosenServerId, initialMessage.getAuthor().getIdLong()).thenCompose(member -> {
try { try {
return self.createModMailThreadForUser(member, initialMessage, initialMessage.getChannel(), true, undoActions); return self.createModMailThreadForUser(member, initialMessage, true, undoActions).thenApply(messageChannel -> null);
} catch (Exception exception) { } catch (Exception exception) {
CompletableFuture<Void> future = new CompletableFuture<>(); CompletableFuture<Void> future = new CompletableFuture<>();
future.completeExceptionally(exception); future.completeExceptionally(exception);

View File

@@ -0,0 +1,5 @@
package dev.sheldan.abstracto.modmail.config;
public class ModMailSlashCommandNames {
public static final String MODMAIL = "modmail";
}

View File

@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.modmail.model;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import net.dv8tion.jda.api.entities.Channel;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
@Getter @Getter
@@ -12,5 +13,6 @@ public class ClosingContext {
private Boolean notifyUser; private Boolean notifyUser;
private Boolean log; private Boolean log;
private Member closingMember; private Member closingMember;
private Channel channel;
private String note; private String note;
} }

View File

@@ -4,12 +4,12 @@ import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.entities.MessageChannel;
@Getter @Getter
@Setter @Setter
@Builder @Builder
public class ContactNotificationModel { public class ContactNotificationModel {
private Member targetMember; private Member targetMember;
private TextChannel createdChannel; private MessageChannel createdChannel;
} }

View File

@@ -1,11 +1,10 @@
package dev.sheldan.abstracto.modmail.model.template; package dev.sheldan.abstracto.modmail.model.template;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
import dev.sheldan.abstracto.core.utils.ChannelUtils; import dev.sheldan.abstracto.core.utils.ChannelUtils;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread; import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder;
/** /**
* This model is used to notify a staff member that there is already a mod mail thread open for the user * This model is used to notify a staff member that there is already a mod mail thread open for the user
@@ -13,8 +12,8 @@ import lombok.experimental.SuperBuilder;
*/ */
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class ModMailThreadExistsModel extends UserInitiatedServerContext { public class ModMailThreadExistsModel {
private ModMailThread existingModMailThread; private ModMailThread existingModMailThread;
public String getThreadUrl() { public String getThreadUrl() {

View File

@@ -7,10 +7,8 @@ import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.modmail.model.ClosingContext; import dev.sheldan.abstracto.modmail.model.ClosingContext;
import dev.sheldan.abstracto.modmail.model.database.ModMailThread; import dev.sheldan.abstracto.modmail.model.database.ModMailThread;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -25,12 +23,14 @@ public interface ModMailThreadService {
* the necessary data in the database, notifying the users and sending messages related to the creation of the {@link ModMailThread} * the necessary data in the database, notifying the users and sending messages related to the creation of the {@link ModMailThread}
* @param member The {@link AUserInAServer} to create the mod mail thread for * @param member The {@link AUserInAServer} to create the mod mail thread for
* @param initialMessage The initial message sparking this mod mail thread, null in case it was created by a command * @param initialMessage The initial message sparking this mod mail thread, null in case it was created by a command
* @param feedBackChannel The {@link MessageChannel} in which feedback about exceptions should be posted to
* @param userInitiated Whether or not the mod mail thread was initiated by a user * @param userInitiated Whether or not the mod mail thread was initiated by a user
* @param undoActions A list of {@link dev.sheldan.abstracto.core.models.UndoAction actions} to be undone in case the operation fails. This list will be filled in the method. * @param undoActions A list of {@link dev.sheldan.abstracto.core.models.UndoAction actions} to be undone in case the operation fails. This list will be filled in the method.
* @return A {@link CompletableFuture future} which completes when the modmail thread is set up * @return A {@link CompletableFuture future} which completes when the modmail thread is set up
*/ */
CompletableFuture<Void> createModMailThreadForUser(Member member, Message initialMessage, MessageChannel feedBackChannel, boolean userInitiated, List<UndoActionInstance> undoActions); CompletableFuture<MessageChannel> createModMailThreadForUser(Member member, Message initialMessage, boolean userInitiated, List<UndoActionInstance> undoActions);
CompletableFuture<Void> sendContactNotification(Member member, MessageChannel createdMessageChannel, MessageChannel feedBackChannel);
CompletableFuture<Void> sendContactNotification(Member member, MessageChannel createdMessageChannel, InteractionHook interactionHook);
/** /**
* Changes the configuration value of the category used to create mod mail threads to the given ID. * Changes the configuration value of the category used to create mod mail threads to the given ID.

View File

@@ -5,24 +5,32 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; 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 dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.core.utils.SnowflakeUtils;
import dev.sheldan.abstracto.remind.config.RemindFeatureDefinition; import dev.sheldan.abstracto.remind.config.RemindFeatureDefinition;
import dev.sheldan.abstracto.remind.config.RemindSlashCommandNames;
import dev.sheldan.abstracto.remind.model.database.Reminder; import dev.sheldan.abstracto.remind.model.database.Reminder;
import dev.sheldan.abstracto.remind.model.template.commands.ReminderModel; import dev.sheldan.abstracto.remind.model.template.commands.ReminderModel;
import dev.sheldan.abstracto.remind.service.ReminderService; import dev.sheldan.abstracto.remind.service.ReminderService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -31,44 +39,107 @@ import java.util.concurrent.CompletableFuture;
public class Remind extends AbstractConditionableCommand { public class Remind extends AbstractConditionableCommand {
public static final String REMINDER_EMBED_KEY = "remind_response"; public static final String REMINDER_EMBED_KEY = "remind_response";
public static final String DURATION_PARAMETER = "duration";
public static final String REMIND_TEXT_PARAMETER = "remindText";
@Autowired @Autowired
private ReminderService remindService; private ReminderService remindService;
@Autowired
private TemplateService templateService;
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
Duration remindTime = (Duration) parameters.get(0); Duration remindTime = (Duration) parameters.get(0);
String text = (String) parameters.get(1); String text = (String) parameters.get(1);
Long serverId = commandContext.getGuild().getIdLong();
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor()); AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor());
ReminderModel remindModel = (ReminderModel) ContextConverter.fromCommandContext(commandContext, ReminderModel.class);
remindModel.setRemindText(text);
Reminder createdReminder = remindService.createReminderInForUser(aUserInAServer, text, remindTime, commandContext.getMessage()); Reminder createdReminder = remindService.createReminderInForUser(aUserInAServer, text, remindTime, commandContext.getMessage());
ReminderModel remindModel = ReminderModel
.builder()
.remindText(text)
.member(commandContext.getAuthor())
.reminder(createdReminder)
.build();
remindModel.setReminder(createdReminder); remindModel.setReminder(createdReminder);
log.info("Notifying user {} about reminder being scheduled.", commandContext.getAuthor().getId()); log.info("Notifying user {} about reminder being scheduled.", commandContext.getAuthor().getId());
MessageToSend messageToSend = templateService.renderEmbedTemplate(REMINDER_EMBED_KEY, remindModel, serverId);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(REMINDER_EMBED_KEY, remindModel, commandContext.getChannel())) return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
String durationString = slashCommandParameterService.getCommandOption(DURATION_PARAMETER, event, Duration.class, String.class);
Duration duration = ParseUtils.parseDuration(durationString);
String reminderText = slashCommandParameterService.getCommandOption(REMIND_TEXT_PARAMETER, event, String.class, String.class);
Long serverId = event.getGuild().getIdLong();
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(event.getMember());
Long snowFlake = SnowflakeUtils.createSnowFlake();
Reminder createdReminder = remindService.createReminderInForUser(aUserInAServer, reminderText, duration, event.getChannel().getIdLong(), snowFlake);
ReminderModel remindModel = ReminderModel
.builder()
.remindText(reminderText)
.member(event.getMember())
.reminder(createdReminder)
.build();
remindModel.setReminder(createdReminder);
log.info("Notifying user {} about reminder being scheduled.", event.getMember().getId());
MessageToSend messageToSend = templateService.renderEmbedTemplate(REMINDER_EMBED_KEY, remindModel, serverId);
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter durationParameter = Parameter
parameters.add(Parameter.builder().name("duration").type(Duration.class).templated(true).build()); .builder()
parameters.add(Parameter.builder().name("remindText").type(String.class).templated(true).remainder(true).build()); .name(DURATION_PARAMETER)
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build(); .type(Duration.class)
.templated(true)
.build();
Parameter remindTextParameter = Parameter
.builder()
.name(REMIND_TEXT_PARAMETER)
.type(String.class)
.templated(true)
.remainder(true)
.build();
List<Parameter> parameters = Arrays.asList(durationParameter, remindTextParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.hasExample(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(RemindSlashCommandNames.REMIND)
.commandName("create")
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("remind") .name("remind")
.async(true) .async(true)
.module(UtilityModuleDefinition.UTILITY) .module(UtilityModuleDefinition.UTILITY)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(false) .causesReaction(false)
.parameters(parameters) .parameters(parameters)

View File

@@ -4,26 +4,33 @@ 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.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.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.ServerChannelMessage; import dev.sheldan.abstracto.core.models.ServerChannelMessage;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; 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 dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.remind.config.RemindFeatureDefinition; import dev.sheldan.abstracto.remind.config.RemindFeatureDefinition;
import dev.sheldan.abstracto.remind.config.RemindSlashCommandNames;
import dev.sheldan.abstracto.remind.model.database.Reminder; import dev.sheldan.abstracto.remind.model.database.Reminder;
import dev.sheldan.abstracto.remind.model.template.commands.ReminderDisplay; import dev.sheldan.abstracto.remind.model.template.commands.ReminderDisplay;
import dev.sheldan.abstracto.remind.model.template.commands.RemindersModel; import dev.sheldan.abstracto.remind.model.template.commands.RemindersModel;
import dev.sheldan.abstracto.remind.service.management.ReminderManagementService; import dev.sheldan.abstracto.remind.service.management.ReminderManagementService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@Component @Component
@Slf4j @Slf4j
@@ -39,38 +46,75 @@ public class Reminders extends AbstractConditionableCommand {
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private TemplateService templateService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(commandContext.getAuthor()); Long serverId = commandContext.getGuild().getIdLong();
Member member = commandContext.getAuthor();
MessageToSend messageToSend = getMessageToSend(serverId, member);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromIgnored());
}
private MessageToSend getMessageToSend(Long serverId, Member member) {
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(member);
List<Reminder> activeReminders = reminderManagementService.getActiveRemindersForUser(aUserInAServer); List<Reminder> activeReminders = reminderManagementService.getActiveRemindersForUser(aUserInAServer);
RemindersModel model = (RemindersModel) ContextConverter.fromCommandContext(commandContext, RemindersModel.class); List<ReminderDisplay> reminders = activeReminders.stream().map(reminder -> {
activeReminders.forEach(reminder -> {
ServerChannelMessage originMessage = ServerChannelMessage ServerChannelMessage originMessage = ServerChannelMessage
.builder() .builder()
.messageId(reminder.getMessageId()) .messageId(reminder.getMessageId())
.channelId(reminder.getChannel().getId()) .channelId(reminder.getChannel().getId())
.serverId(commandContext.getGuild().getIdLong()) .serverId(serverId)
.build(); .build();
ReminderDisplay display = ReminderDisplay return ReminderDisplay
.builder() .builder()
.reminder(reminder) .reminder(reminder)
.message(originMessage) .message(originMessage)
.build(); .build();
model.getReminders().add(display); }).collect(Collectors.toList());
}); RemindersModel model = RemindersModel
log.info("Showing {} reminders for user {} in server {}.", activeReminders.size(), commandContext.getAuthor().getId(), commandContext.getGuild().getId()); .builder()
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(REMINDERS_RESPONSE_TEMPLATE, model, commandContext.getChannel())) .reminders(reminders)
.thenApply(aVoid -> CommandResult.fromIgnored()); .member(member)
.build();
log.info("Showing {} reminders for user {} in server {}.", activeReminders.size(), aUserInAServer.getUserReference().getId(), serverId);
return templateService.renderEmbedTemplate(REMINDERS_RESPONSE_TEMPLATE, model, serverId);
}
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Long serverId = event.getGuild().getIdLong();
Member member = event.getMember();
MessageToSend messageToSend = getMessageToSend(serverId, member);
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
} }
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(RemindSlashCommandNames.REMIND)
.commandName("list")
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("reminders") .name("reminders")
.async(true) .async(true)
.module(UtilityModuleDefinition.UTILITY) .module(UtilityModuleDefinition.UTILITY)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)
.help(helpInfo) .help(helpInfo)

View File

@@ -5,29 +5,47 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.utils.ParseUtils;
import dev.sheldan.abstracto.remind.config.RemindFeatureDefinition; import dev.sheldan.abstracto.remind.config.RemindFeatureDefinition;
import dev.sheldan.abstracto.remind.config.RemindSlashCommandNames;
import dev.sheldan.abstracto.remind.service.ReminderService; import dev.sheldan.abstracto.remind.service.ReminderService;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component @Component
public class Snooze extends AbstractConditionableCommand { public class Snooze extends AbstractConditionableCommand {
private static final String SNOOZE_COMMAND = "snooze";
private static final String DURATION_PARAMETER = "duration";
private static final String REMINDER_ID_PARAMETER = "reminderId";
private static final String SNOOZE_RESPONSE = "snooze_response";
@Autowired @Autowired
private ReminderService reminderService; private ReminderService reminderService;
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private InteractionService interactionService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
List<Object> newParameters = commandContext.getParameters().getParameters(); List<Object> newParameters = commandContext.getParameters().getParameters();
@@ -38,18 +56,51 @@ public class Snooze extends AbstractConditionableCommand {
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Long reminderId = slashCommandParameterService.getCommandOption(REMINDER_ID_PARAMETER, event, Long.class, Integer.class).longValue();
String newDurationString = slashCommandParameterService.getCommandOption(DURATION_PARAMETER, event, String.class, String.class);
Duration newDuration = ParseUtils.parseDuration(newDurationString);
AUserInAServer aUserInAServer = userInServerManagementService.loadOrCreateUser(event.getMember());
reminderService.snoozeReminder(reminderId, aUserInAServer, newDuration);
return interactionService.replyEmbed(SNOOZE_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter reminderParameter = Parameter
parameters.add(Parameter.builder().name("reminderId").type(Long.class).templated(true).build()); .builder()
parameters.add(Parameter.builder().name("duration").type(Duration.class).templated(true).build()); .name(REMINDER_ID_PARAMETER)
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .type(Long.class)
.templated(true)
.build();
Parameter durationParameter = Parameter
.builder()
.name(DURATION_PARAMETER)
.type(Duration.class)
.templated(true)
.build();
List<Parameter> parameters = Arrays.asList(reminderParameter, durationParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(RemindSlashCommandNames.REMIND)
.commandName(SNOOZE_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("snooze") .name(SNOOZE_COMMAND)
.module(UtilityModuleDefinition.UTILITY) .module(UtilityModuleDefinition.UTILITY)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(true) .causesReaction(true)
.slashCommandConfig(slashCommandConfig)
.parameters(parameters) .parameters(parameters)
.help(helpInfo) .help(helpInfo)
.build(); .build();

View File

@@ -2,35 +2,45 @@ package dev.sheldan.abstracto.remind.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.CommandConfiguration; import dev.sheldan.abstracto.core.command.config.*;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.ParameterValidator;
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.remind.config.RemindFeatureDefinition; import dev.sheldan.abstracto.remind.config.RemindFeatureDefinition;
import dev.sheldan.abstracto.remind.config.RemindSlashCommandNames;
import dev.sheldan.abstracto.remind.service.ReminderService; import dev.sheldan.abstracto.remind.service.ReminderService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
@Slf4j @Slf4j
@Component @Component
public class UnRemind extends AbstractConditionableCommand { public class UnRemind extends AbstractConditionableCommand {
private static final String UN_REMIND_COMMAND = "unRemind";
private static final String REMINDER_ID_PARAMETER = "reminderId";
private static final String UN_REMIND_RESPONSE = "unRemind_response";
@Autowired @Autowired
private ReminderService reminderService; private ReminderService reminderService;
@Autowired @Autowired
private UserInServerManagementService userInServerManagementService; private UserInServerManagementService userInServerManagementService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
Long reminderId = (Long) commandContext.getParameters().getParameters().get(0); Long reminderId = (Long) commandContext.getParameters().getParameters().get(0);
@@ -38,17 +48,41 @@ public class UnRemind extends AbstractConditionableCommand {
return CommandResult.fromSuccess(); return CommandResult.fromSuccess();
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
Long reminderId = slashCommandParameterService.getCommandOption(REMINDER_ID_PARAMETER, event, Long.class, Integer.class).longValue();
reminderService.unRemind(reminderId, userInServerManagementService.loadOrCreateUser(event.getMember()));
return interactionService.replyEmbed(UN_REMIND_RESPONSE, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); Parameter reminderParameter = Parameter
List<ParameterValidator> reminderIdValidator = Arrays.asList(MinIntegerValueValidator.min(1L)); .builder()
parameters.add(Parameter.builder().name("reminderId").validators(reminderIdValidator).templated(true).type(Long.class).build()); .name(REMINDER_ID_PARAMETER)
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); .templated(true)
.type(Long.class)
.build();
List<Parameter> parameters = Arrays.asList(reminderParameter);
HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(RemindSlashCommandNames.REMIND)
.commandName("cancel")
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("unRemind") .name(UN_REMIND_COMMAND)
.module(UtilityModuleDefinition.UTILITY) .module(UtilityModuleDefinition.UTILITY)
.templated(true) .templated(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.slashCommandConfig(slashCommandConfig)
.causesReaction(true) .causesReaction(true)
.parameters(parameters) .parameters(parameters)
.help(helpInfo) .help(helpInfo)

View File

@@ -92,6 +92,11 @@ public class RemindServiceBean implements ReminderService {
return reminder; return reminder;
} }
@Override
public Reminder createReminderInForUser(AUserInAServer user, String remindText, Duration remindIn, Long channelId) {
return createReminderInForUser(user, remindText, remindIn, channelId, null);
}
private void scheduleReminder(Duration remindIn, Reminder reminder) { private void scheduleReminder(Duration remindIn, Reminder reminder) {
if(remindIn.getSeconds() < 60) { if(remindIn.getSeconds() < 60) {
reminder.setJobTriggerKey(null); reminder.setJobTriggerKey(null);

View File

@@ -38,6 +38,11 @@ public class ReminderManagementServiceBean implements ReminderManagementService
return reminderRepository.save(reminder); return reminderRepository.save(reminder);
} }
@Override
public Reminder createReminder(AServerAChannelAUser userToBeReminded, String text, Instant timeToBeRemindedAt) {
return null;
}
@Override @Override
public Optional<Reminder> loadReminderOptional(Long reminderId) { public Optional<Reminder> loadReminderOptional(Long reminderId) {
return reminderRepository.findById(reminderId); return reminderRepository.findById(reminderId);

View File

@@ -1,63 +0,0 @@
package dev.sheldan.abstracto.remind.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.remind.model.template.commands.ReminderModel;
import dev.sheldan.abstracto.remind.service.ReminderService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Duration;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class RemindTest {
@InjectMocks
private Remind testUnit;
@Mock
private ReminderService remindService;
@Mock
private ChannelService channelService;
@Mock
private UserInServerManagementService userInServerManagementService;
@Captor
private ArgumentCaptor<ReminderModel> captor;
@Test
public void executeCommand() {
String reminderText = "text";
Duration duration = Duration.ofMinutes(10);
CommandContext withParameters = CommandTestUtilities.getWithParameters(Arrays.asList(duration, reminderText));
AUserInAServer user = Mockito.mock(AUserInAServer.class);
when(userInServerManagementService.loadOrCreateUser(withParameters.getAuthor())).thenReturn(user);
CompletableFuture<CommandResult> result = testUnit.executeAsync(withParameters);
verify(remindService, times(1)).createReminderInForUser(user, reminderText, duration, withParameters.getMessage());
verify(channelService, times(1)).sendEmbedTemplateInTextChannelList(eq(Remind.REMINDER_EMBED_KEY), captor.capture(), eq(withParameters.getChannel()));
ReminderModel reminderModel = captor.getValue();
Assert.assertEquals(reminderText, reminderModel.getRemindText());
Assert.assertEquals(withParameters.getMessage(), reminderModel.getMessage());
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -1,72 +0,0 @@
package dev.sheldan.abstracto.remind.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.core.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.core.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.remind.model.database.Reminder;
import dev.sheldan.abstracto.remind.model.template.commands.RemindersModel;
import dev.sheldan.abstracto.remind.service.management.ReminderManagementService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class RemindersTest {
@InjectMocks
private Reminders testUnit;
@Mock
private ReminderManagementService reminderManagementService;
@Mock
private ChannelService channelService;
@Mock
private UserInServerManagementService userInServerManagementService;
@Mock
private AChannel channel;
@Captor
private ArgumentCaptor<RemindersModel> modelCaptor;
@Test
public void testExecuteCommand() {
CommandContext context = CommandTestUtilities.getNoParameters();
Reminder reminder = Mockito.mock(Reminder.class);
when(reminder.getChannel()).thenReturn(channel);
Reminder secondReminder = Mockito.mock(Reminder.class);
when(secondReminder.getChannel()).thenReturn(channel);
List<Reminder> reminders = Arrays.asList(reminder, secondReminder);
AUserInAServer user = Mockito.mock(AUserInAServer.class);
when(userInServerManagementService.loadOrCreateUser(context.getAuthor())).thenReturn(user);
when(reminderManagementService.getActiveRemindersForUser(user)).thenReturn(reminders);
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);
verify(channelService, times(1)).sendEmbedTemplateInTextChannelList(eq(Reminders.REMINDERS_RESPONSE_TEMPLATE), modelCaptor.capture(), eq(context.getChannel()));
RemindersModel usedModel = modelCaptor.getValue();
Assert.assertEquals(reminder, usedModel.getReminders().get(0).getReminder());
Assert.assertEquals(secondReminder, usedModel.getReminders().get(1).getReminder());
Assert.assertEquals(reminders.size(), usedModel.getReminders().size());
CommandTestUtilities.checkSuccessfulCompletionAsync(result);
}
@Test
public void validateCommand() {
CommandConfigValidator.validateCommandConfiguration(testUnit.getConfiguration());
}
}

View File

@@ -0,0 +1,5 @@
package dev.sheldan.abstracto.remind.config;
public class RemindSlashCommandNames {
public static final String REMIND = "remind";
}

View File

@@ -1,15 +1,16 @@
package dev.sheldan.abstracto.remind.model.template.commands; package dev.sheldan.abstracto.remind.model.template.commands;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
import dev.sheldan.abstracto.remind.model.database.Reminder; import dev.sheldan.abstracto.remind.model.database.Reminder;
import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder; import net.dv8tion.jda.api.entities.Member;
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class ReminderModel extends UserInitiatedServerContext { public class ReminderModel {
private String remindText; private String remindText;
private Member member;
private Reminder reminder; private Reminder reminder;
} }

View File

@@ -1,18 +1,18 @@
package dev.sheldan.abstracto.remind.model.template.commands; package dev.sheldan.abstracto.remind.model.template.commands;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.SuperBuilder; import net.dv8tion.jda.api.entities.Member;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Getter @Getter
@Setter @Setter
@SuperBuilder @Builder
public class RemindersModel extends UserInitiatedServerContext { public class RemindersModel {
@Builder.Default @Builder.Default
private List<ReminderDisplay> reminders = new ArrayList<>(); private List<ReminderDisplay> reminders = new ArrayList<>();
private Member member;
} }

View File

@@ -9,6 +9,7 @@ import java.time.Duration;
public interface ReminderService { public interface ReminderService {
Reminder createReminderInForUser(AUserInAServer user, String remindText, Duration remindIn, Message message); Reminder createReminderInForUser(AUserInAServer user, String remindText, Duration remindIn, Message message);
Reminder createReminderInForUser(AUserInAServer user, String remindText, Duration remindIn, Long channelId, Long messageId); Reminder createReminderInForUser(AUserInAServer user, String remindText, Duration remindIn, Long channelId, Long messageId);
Reminder createReminderInForUser(AUserInAServer user, String remindText, Duration remindIn, Long channelId);
void executeReminder(Long reminderId); void executeReminder(Long reminderId);
void unRemind(Long reminderId, AUserInAServer userInAServer); void unRemind(Long reminderId, AUserInAServer userInAServer);
void snoozeReminder(Long reminderId, AUserInAServer user, Duration newDuration); void snoozeReminder(Long reminderId, AUserInAServer user, Duration newDuration);

View File

@@ -10,6 +10,7 @@ import java.util.Optional;
public interface ReminderManagementService { public interface ReminderManagementService {
Reminder createReminder(AServerAChannelAUser userToBeReminded, String text, Instant timeToBeRemindedAt, Long messageId); Reminder createReminder(AServerAChannelAUser userToBeReminded, String text, Instant timeToBeRemindedAt, Long messageId);
Reminder createReminder(AServerAChannelAUser userToBeReminded, String text, Instant timeToBeRemindedAt);
Optional<Reminder> loadReminderOptional(Long reminderId); Optional<Reminder> loadReminderOptional(Long reminderId);
Reminder loadReminder(Long reminderId); Reminder loadReminder(Long reminderId);
void setReminded(Reminder reminder); void setReminded(Reminder reminder);

View File

@@ -5,15 +5,22 @@ import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand
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;
import dev.sheldan.abstracto.core.command.config.SlashCommandConfig;
import dev.sheldan.abstracto.core.command.execution.CommandContext; import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.slash.parameter.SlashCommandParameterService;
import dev.sheldan.abstracto.core.config.FeatureDefinition; import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.interaction.InteractionService;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
import dev.sheldan.abstracto.core.templating.service.TemplateService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.starboard.config.StarboardFeatureDefinition; import dev.sheldan.abstracto.starboard.config.StarboardFeatureDefinition;
import dev.sheldan.abstracto.starboard.config.StarboardSlashCommandNames;
import dev.sheldan.abstracto.starboard.model.template.MemberStarStatsModel; import dev.sheldan.abstracto.starboard.model.template.MemberStarStatsModel;
import dev.sheldan.abstracto.starboard.service.StarboardService; import dev.sheldan.abstracto.starboard.service.StarboardService;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -26,6 +33,8 @@ public class StarStats extends AbstractConditionableCommand {
public static final String STARSTATS_RESPONSE_TEMPLATE = "starStats_response"; public static final String STARSTATS_RESPONSE_TEMPLATE = "starStats_response";
public static final String STARSTATS_SINGLE_MEMBER_RESPONSE_TEMPLATE = "starStats_single_member_response"; public static final String STARSTATS_SINGLE_MEMBER_RESPONSE_TEMPLATE = "starStats_single_member_response";
private static final String STAR_STATS_COMMAND = "starStats";
private static final String MEMBER_PARAMETER = "member";
@Autowired @Autowired
private StarboardService starboardService; private StarboardService starboardService;
@@ -33,31 +42,77 @@ public class StarStats extends AbstractConditionableCommand {
@Autowired @Autowired
private ChannelService channelService; private ChannelService channelService;
@Autowired
private TemplateService templateService;
@Autowired
private SlashCommandParameterService slashCommandParameterService;
@Autowired
private InteractionService interactionService;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
if(parameters.isEmpty()) { if(parameters.isEmpty()) {
return starboardService.retrieveStarStats(commandContext.getGuild().getIdLong()) return starboardService.retrieveStarStats(commandContext.getGuild().getIdLong())
.thenCompose(starStatsModel -> .thenCompose(starStatsModel -> {
FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(STARSTATS_RESPONSE_TEMPLATE, starStatsModel, commandContext.getChannel())) MessageToSend messageToSend = templateService.renderEmbedTemplate(STARSTATS_RESPONSE_TEMPLATE, starStatsModel, commandContext.getGuild().getIdLong());
).thenApply(o -> CommandResult.fromIgnored()); return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()));
}).thenApply(o -> CommandResult.fromIgnored());
} else { } else {
Member targetMember = (Member) parameters.get(0); Member targetMember = (Member) parameters.get(0);
MemberStarStatsModel memberStarStatsModel = starboardService.retrieveStarStatsForMember(targetMember); MemberStarStatsModel memberStarStatsModel = starboardService.retrieveStarStatsForMember(targetMember);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInTextChannelList(STARSTATS_SINGLE_MEMBER_RESPONSE_TEMPLATE, memberStarStatsModel, commandContext.getChannel())) MessageToSend messageToSend = templateService.renderEmbedTemplate(STARSTATS_SINGLE_MEMBER_RESPONSE_TEMPLATE, memberStarStatsModel, commandContext.getGuild().getIdLong());
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(unused -> CommandResult.fromIgnored()); .thenApply(unused -> CommandResult.fromIgnored());
} }
} }
@Override
public CompletableFuture<CommandResult> executeSlash(SlashCommandInteractionEvent event) {
if(slashCommandParameterService.hasCommandOption(MEMBER_PARAMETER, event)) {
Member targetMember = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER, event, Member.class, Member.class);
MemberStarStatsModel memberStarStatsModel = starboardService.retrieveStarStatsForMember(targetMember);
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARSTATS_SINGLE_MEMBER_RESPONSE_TEMPLATE, memberStarStatsModel, event.getGuild().getIdLong());
return interactionService.replyMessageToSend(messageToSend, event)
.thenApply(interactionHook -> CommandResult.fromSuccess());
} else {
return starboardService.retrieveStarStats(event.getGuild().getIdLong())
.thenCompose(starStatsModel -> {
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARSTATS_RESPONSE_TEMPLATE, starStatsModel, event.getGuild().getIdLong());
return interactionService.replyMessageToSend(messageToSend, event);
}).thenApply(o -> CommandResult.fromIgnored());
}
}
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
Parameter memberParameter = Parameter.builder().templated(true).name("member").type(Member.class).optional(true).build(); Parameter memberParameter = Parameter
.builder()
.templated(true)
.name(MEMBER_PARAMETER)
.type(Member.class)
.optional(true)
.build();
List<Parameter> parameters = Collections.singletonList(memberParameter); List<Parameter> parameters = Collections.singletonList(memberParameter);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build(); HelpInfo helpInfo = HelpInfo
.builder()
.templated(true)
.build();
SlashCommandConfig slashCommandConfig = SlashCommandConfig
.builder()
.enabled(true)
.rootCommandName(StarboardSlashCommandNames.STARBOARD)
.commandName(STAR_STATS_COMMAND)
.build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("starStats") .name(STAR_STATS_COMMAND)
.module(UtilityModuleDefinition.UTILITY) .module(UtilityModuleDefinition.UTILITY)
.templated(true) .templated(true)
.slashCommandConfig(slashCommandConfig)
.async(true) .async(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.causesReaction(false) .causesReaction(false)

Some files were not shown because too many files have changed in this diff Show More