added conventions for templated commands, to reduce the amount of necessary configuration

added an exception, in case the command was missing the correct types of parameters (channel is required, no channel was found)
added fix text to exception handler, in case the message of an exception is null
fixed off-by-one error when searching the missing parameter
changed supported chanel from guildChannel to textChannel for posttarget
added slowmode command
This commit is contained in:
Sheldan
2020-03-18 21:06:27 +01:00
parent 9119d57108
commit ec21305725
21 changed files with 212 additions and 42 deletions

View File

@@ -53,11 +53,11 @@ public class Ban implements Command {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("user").type(Member.class).optional(false).build()); parameters.add(Parameter.builder().name("user").type(Member.class).optional(false).build());
parameters.add(Parameter.builder().name("reason").type(String.class).optional(true).remainder(true).build()); parameters.add(Parameter.builder().name("reason").type(String.class).optional(true).remainder(true).build());
HelpInfo helpInfo = HelpInfo.builder().usageTemplate("ban_usage").longHelpTemplate("ban_long_help").build(); HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("ban") .name("ban")
.module(Moderation.MODERATION) .module(Moderation.MODERATION)
.descriptionTemplate("ban_help_description") .templated(true)
.causesReaction(true) .causesReaction(true)
.parameters(parameters) .parameters(parameters)
.help(helpInfo) .help(helpInfo)

View File

@@ -50,11 +50,11 @@ public class Kick implements Command {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("user").type(Member.class).optional(false).build()); parameters.add(Parameter.builder().name("user").type(Member.class).optional(false).build());
parameters.add(Parameter.builder().name("reason").type(String.class).optional(true).remainder(true).build()); parameters.add(Parameter.builder().name("reason").type(String.class).optional(true).remainder(true).build());
HelpInfo helpInfo = HelpInfo.builder().usageTemplate("kick_usage").longHelpTemplate("kick_long_help").build(); HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("kick") .name("kick")
.module(Moderation.MODERATION) .module(Moderation.MODERATION)
.descriptionTemplate("kick_help_description") .templated(true)
.causesReaction(true) .causesReaction(true)
.parameters(parameters) .parameters(parameters)
.help(helpInfo) .help(helpInfo)

View File

@@ -0,0 +1,56 @@
package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.command.Command;
import dev.sheldan.abstracto.command.HelpInfo;
import dev.sheldan.abstracto.command.execution.CommandConfiguration;
import dev.sheldan.abstracto.command.execution.CommandContext;
import dev.sheldan.abstracto.command.execution.Parameter;
import dev.sheldan.abstracto.command.execution.Result;
import dev.sheldan.abstracto.moderation.Moderation;
import dev.sheldan.abstracto.moderation.service.SlowModeService;
import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@Component
public class SlowMode implements Command {
@Autowired
private SlowModeService slowModeService;
@Override
public Result execute(CommandContext commandContext) {
TextChannel channel;
long seconds = (Long) commandContext.getParameters().getParameters().get(0);
if(commandContext.getParameters().getParameters().size() == 2) {
channel = (TextChannel) commandContext.getParameters().getParameters().get(1);
if(commandContext.getGuild().getGuildChannelById(channel.getIdLong()) == null) {
throw new IllegalArgumentException("Given channel was not part of the current guild.");
}
} else {
channel = commandContext.getChannel();
}
slowModeService.setSlowMode(channel, Duration.ofSeconds(seconds));
return Result.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("seconds").type(Long.class).optional(false).build());
parameters.add(Parameter.builder().name("channel").type(TextChannel.class).optional(true).build());
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("slowmode")
.module(Moderation.MODERATION)
.templated(true)
.causesReaction(true)
.parameters(parameters)
.help(helpInfo)
.build();
}
}

View File

@@ -56,11 +56,11 @@ public class Warn implements Command {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("user").type(Member.class).optional(false).build()); parameters.add(Parameter.builder().name("user").type(Member.class).optional(false).build());
parameters.add(Parameter.builder().name("reason").type(String.class).optional(true).remainder(true).build()); parameters.add(Parameter.builder().name("reason").type(String.class).optional(true).remainder(true).build());
HelpInfo helpInfo = HelpInfo.builder().usageTemplate("warn_usage").longHelpTemplate("long_help").build(); HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("warn") .name("warn")
.module(Moderation.MODERATION) .module(Moderation.MODERATION)
.descriptionTemplate("warn_help_description") .templated(true)
.causesReaction(true) .causesReaction(true)
.parameters(parameters) .parameters(parameters)
.help(helpInfo) .help(helpInfo)

View File

@@ -0,0 +1,45 @@
package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.models.AChannel;
import dev.sheldan.abstracto.core.service.Bot;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
@Component
@Slf4j
public class SlowModeServiceBean implements SlowModeService {
@Autowired
private Bot bot;
@Override
public void setSlowMode(TextChannel channel, Duration duration) {
long seconds = duration.getSeconds();
if(seconds > TextChannel.MAX_SLOWMODE) {
throw new IllegalArgumentException("Slow mode duration must be < " + TextChannel.MAX_SLOWMODE + " seconds.");
}
channel.getManager().setSlowmode((int) seconds).queue();
}
@Override
public void setSlowMode(AChannel channel, Duration duration) {
JDA jpaInstance = bot.getInstance();
Guild guild = jpaInstance.getGuildById(channel.getServer().getId());
if(guild != null) {
TextChannel textChannelById = guild.getTextChannelById(channel.getId());
if(textChannelById != null) {
this.setSlowMode(textChannelById, duration);
} else {
log.warn("Channel {} was not found in guild {} when trying to set a slow mode.", channel.getId(), channel.getServer().getId());
}
} else {
log.warn("Guild {} was not found when trying to set slow mode.", channel.getServer().getId());
}
}
}

View File

@@ -0,0 +1 @@
Sets the slow mode of the the current (or given channel) to the given seconds.

View File

@@ -0,0 +1 @@
The slowmode in channel ${channel.name} has been set to ${channel.slowMode} seconds.

View File

@@ -0,0 +1 @@
Sets the slow mode of the the current (or given channel) to the given seconds.

View File

@@ -0,0 +1,11 @@
package dev.sheldan.abstracto.moderation.service;
import dev.sheldan.abstracto.core.models.AChannel;
import net.dv8tion.jda.api.entities.TextChannel;
import java.time.Duration;
public interface SlowModeService {
void setSlowMode(TextChannel channel, Duration duration);
void setSlowMode(AChannel channel, Duration duration);
}

View File

@@ -7,6 +7,5 @@ import lombok.Getter;
public class HelpInfo { public class HelpInfo {
private String usage; private String usage;
private String longHelp; private String longHelp;
private String longHelpTemplate; private boolean templated;
private String usageTemplate;
} }

View File

@@ -13,9 +13,9 @@ public class CommandConfiguration {
private String name; private String name;
private String module; private String module;
private String description; private String description;
private String descriptionTemplate;
private List<Parameter> parameters; private List<Parameter> parameters;
private boolean causesReaction; private boolean causesReaction;
private boolean templated;
private HelpInfo help; private HelpInfo help;
public int getNecessaryParameterCount(){ public int getNecessaryParameterCount(){

View File

@@ -34,7 +34,7 @@ public class CommandManager implements CommandRegistry {
boolean paramCountFits = unParsedCommandParameter.getParameters().size() >= commandConfiguration.getNecessaryParameterCount(); boolean paramCountFits = unParsedCommandParameter.getParameters().size() >= commandConfiguration.getNecessaryParameterCount();
boolean hasRemainderParameter = commandConfiguration.getParameters().stream().anyMatch(Parameter::isRemainder); boolean hasRemainderParameter = commandConfiguration.getParameters().stream().anyMatch(Parameter::isRemainder);
if(unParsedCommandParameter.getParameters().size() < commandConfiguration.getNecessaryParameterCount()) { if(unParsedCommandParameter.getParameters().size() < commandConfiguration.getNecessaryParameterCount()) {
String nextParameterName = commandConfiguration.getParameters().get(commandConfiguration.getNecessaryParameterCount()).getName(); String nextParameterName = commandConfiguration.getParameters().get(commandConfiguration.getNecessaryParameterCount() - 1).getName();
throw new InsufficientParametersException("Insufficient parameters", o, nextParameterName); throw new InsufficientParametersException("Insufficient parameters", o, nextParameterName);
} }
parameterFit = paramCountFits || hasRemainderParameter; parameterFit = paramCountFits || hasRemainderParameter;

View File

@@ -4,6 +4,8 @@ import dev.sheldan.abstracto.command.Command;
import dev.sheldan.abstracto.command.PostCommandExecution; import dev.sheldan.abstracto.command.PostCommandExecution;
import dev.sheldan.abstracto.command.execution.*; import dev.sheldan.abstracto.command.execution.*;
import dev.sheldan.abstracto.command.meta.UnParsedCommandParameter; import dev.sheldan.abstracto.command.meta.UnParsedCommandParameter;
import dev.sheldan.abstracto.commands.management.exception.IncorrectParameterException;
import dev.sheldan.abstracto.commands.management.exception.InsufficientParametersException;
import dev.sheldan.abstracto.core.management.ChannelManagementService; import dev.sheldan.abstracto.core.management.ChannelManagementService;
import dev.sheldan.abstracto.core.management.ServerManagementService; import dev.sheldan.abstracto.core.management.ServerManagementService;
import dev.sheldan.abstracto.core.models.AChannel; import dev.sheldan.abstracto.core.models.AChannel;
@@ -11,6 +13,7 @@ import dev.sheldan.abstracto.core.models.AServer;
import net.dv8tion.jda.api.entities.GuildChannel; import net.dv8tion.jda.api.entities.GuildChannel;
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.TextChannel;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter; import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -18,9 +21,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays;
import java.util.List;
@Service @Service
public class CommandReceivedHandler extends ListenerAdapter { public class CommandReceivedHandler extends ListenerAdapter {
@@ -84,25 +85,30 @@ public class CommandReceivedHandler extends ListenerAdapter {
public Parameters getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message){ public Parameters getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message){
List<Object> parsedParameters = new ArrayList<>(); List<Object> parsedParameters = new ArrayList<>();
int mentionedChannelsCount = 0; Iterator<TextChannel> channelIterator = message.getMentionedChannels().iterator();
int mentionedUserCount = 0; Iterator<Member> memberIterator = message.getMentionedMembers().iterator();
for (int i = 0; i < unParsedCommandParameter.getParameters().size(); i++) { for (int i = 0; i < unParsedCommandParameter.getParameters().size(); i++) {
Parameter param = command.getConfiguration().getParameters().get(i); Parameter param = command.getConfiguration().getParameters().get(i);
String value = unParsedCommandParameter.getParameters().get(i); String value = unParsedCommandParameter.getParameters().get(i);
if(param.getType().equals(Integer.class)){ try {
parsedParameters.add(Integer.parseInt(value)); if(param.getType().equals(Integer.class)){
} else if(param.getType().equals(Double.class)){ parsedParameters.add(Integer.parseInt(value));
parsedParameters.add(Double.parseDouble(value)); } else if(param.getType().equals(Double.class)){
} else if(param.getType().equals(GuildChannel.class)){ parsedParameters.add(Double.parseDouble(value));
parsedParameters.add(message.getMentionedChannels().get(mentionedChannelsCount)); } else if(param.getType().equals(Long.class)){
mentionedChannelsCount++; parsedParameters.add(Long.parseLong(value));
} else if(param.getType().equals(Member.class)) { } else if(param.getType().equals(TextChannel.class)){
parsedParameters.add(message.getMentionedMembers().get(mentionedUserCount)); parsedParameters.add(channelIterator.next());
mentionedUserCount++; } else if(param.getType().equals(Member.class)) {
} else { parsedParameters.add(memberIterator.next());
parsedParameters.add(value); } else {
parsedParameters.add(value);
}
} catch (NoSuchElementException e) {
throw new IncorrectParameterException("The passed parameters did not have the correct type.", command, param.getType(), param.getName());
}
} }
}
return Parameters.builder().parameters(parsedParameters).build(); return Parameters.builder().parameters(parsedParameters).build();
} }
} }

View File

@@ -0,0 +1,33 @@
package dev.sheldan.abstracto.commands.management.exception;
import dev.sheldan.abstracto.command.Command;
import dev.sheldan.abstracto.command.TemplatedException;
import java.util.HashMap;
public class IncorrectParameterException extends RuntimeException implements TemplatedException {
private Command command;
private String parameterName;
private Class clazz;
public IncorrectParameterException(String s, Command command, Class expected, String parameterName) {
super(s);
this.command = command;
this.parameterName = parameterName;
this.clazz = expected;
}
@Override
public String getTemplateName() {
return "incorrect_parameters";
}
@Override
public Object getTemplateModel() {
HashMap<String, Object> model = new HashMap<>();
model.put("parameterName", parameterName);
model.put("class", this.clazz);
return model;
}
}

View File

@@ -25,7 +25,7 @@ public class ExceptionPostExecution implements PostCommandExecution {
String text = templateService.renderTemplate(exception.getTemplateName(), exception.getTemplateModel()); String text = templateService.renderTemplate(exception.getTemplateName(), exception.getTemplateModel());
commandContext.getChannel().sendMessage(text).queue(); commandContext.getChannel().sendMessage(text).queue();
} else { } else {
commandContext.getChannel().sendMessage(result.getMessage()).queue(); commandContext.getChannel().sendMessage("Exception: " + result.getThrowable().getClass() + ": " + result.getMessage()).queue();
} }
} }
} }

View File

@@ -0,0 +1 @@
The necessary parameters were not found. A '${class.simpleName}' was expected as '${parameterName}'. Consult help to see the correct syntax.

View File

@@ -10,9 +10,9 @@ import dev.sheldan.abstracto.core.management.PostTargetManagement;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.GuildChannel; import net.dv8tion.jda.api.entities.GuildChannel;
import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -39,7 +39,7 @@ public class SetPostTargetCommand implements Command {
@Override @Override
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
Parameter channel = Parameter.builder().name("channel").type(GuildChannel.class).description("The channel to post towards").build(); Parameter channel = Parameter.builder().name("channel").type(TextChannel.class).description("The channel to post towards").build();
Parameter postTargetName = Parameter.builder().name("name").type(String.class).description("The name of the post target to redirect").build(); Parameter postTargetName = Parameter.builder().name("name").type(String.class).description("The name of the post target to redirect").build();
List<Parameter> parameters = Arrays.asList(postTargetName, channel); List<Parameter> parameters = Arrays.asList(postTargetName, channel);
return CommandConfiguration.builder() return CommandConfiguration.builder()

View File

@@ -61,20 +61,35 @@ public class Help implements Command {
CommandConfiguration commandConfiguration = command.getConfiguration(); CommandConfiguration commandConfiguration = command.getConfiguration();
sb.append(String.format("Command: **%s**", commandConfiguration.getName())); sb.append(String.format("Command: **%s**", commandConfiguration.getName()));
sb.append("\n"); sb.append("\n");
sb.append(String.format("Description: %s", getTemplateOrDefault(commandConfiguration.getDescriptionTemplate(), commandConfiguration.getDescription()))); String descriptionTemplate = getDescriptionTemplate(commandConfiguration.getName());
sb.append(String.format("Description: %s", getTemplateOrDefault(commandConfiguration, descriptionTemplate, commandConfiguration.getDescription())));
sb.append("\n"); sb.append("\n");
HelpInfo helpObj = commandConfiguration.getHelp(); HelpInfo helpObj = commandConfiguration.getHelp();
if(helpObj != null){ if(helpObj != null){
sb.append(String.format("Usage: %s", getTemplateOrDefault(helpObj.getUsageTemplate(), helpObj.getUsage()))); String usageTemplate = getUsageTemplate(commandConfiguration.getName());
sb.append(String.format("Usage: %s", getTemplateOrDefault(commandConfiguration, usageTemplate, helpObj.getUsage())));
sb.append("\n"); sb.append("\n");
sb.append(String.format("Detailed help: %s", getTemplateOrDefault(helpObj.getLongHelpTemplate(), helpObj.getLongHelp()))); String longHelpTemplate = getLongHelpTemplate(commandConfiguration.getName());
sb.append(String.format("Detailed help: %s", getTemplateOrDefault(commandConfiguration, longHelpTemplate, helpObj.getLongHelp())));
sb.append("\n"); sb.append("\n");
} }
return sb.toString(); return sb.toString();
} }
private String getTemplateOrDefault(String templateKey, String defaultText) { private String getDescriptionTemplate(String commandName) {
if(templateKey == null) { return commandName + "_description";
}
private String getUsageTemplate(String commandName) {
return commandName + "_usage";
}
private String getLongHelpTemplate(String commandName) {
return commandName + "_long_help";
}
private String getTemplateOrDefault(CommandConfiguration commandConfiguration, String templateKey, String defaultText) {
if(templateKey == null || !commandConfiguration.isTemplated()) {
return defaultText; return defaultText;
} else { } else {
return templateService.renderTemplate(templateKey, null); return templateService.renderTemplate(templateKey, null);

View File

@@ -37,11 +37,11 @@ public class Echo implements Command {
public CommandConfiguration getConfiguration() { public CommandConfiguration getConfiguration() {
List<Parameter> parameters = new ArrayList<>(); List<Parameter> parameters = new ArrayList<>();
parameters.add(Parameter.builder().name("input").type(String.class).remainder(true).build()); parameters.add(Parameter.builder().name("input").type(String.class).remainder(true).build());
HelpInfo helpInfo = HelpInfo.builder().usageTemplate("echo_usage").longHelpTemplate("echo_long_help").build(); HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("echo") .name("echo")
.module("utility") .module("utility")
.descriptionTemplate("echo_description") .templated(true)
.causesReaction(false) .causesReaction(false)
.parameters(parameters) .parameters(parameters)
.help(helpInfo) .help(helpInfo)

View File

@@ -31,7 +31,7 @@ public class Ping implements Command {
return CommandConfiguration.builder() return CommandConfiguration.builder()
.name("ping") .name("ping")
.module("utility") .module("utility")
.descriptionTemplate("ping_description") .templated(true)
.causesReaction(false) .causesReaction(false)
.build(); .build();
} }