[AB-99/AB-66] changed commands to use embeds for exceptions instead of direct messages

added models instead of using HashMaps for exceptions
added a lot of exceptions for different cases
refactored a few commands to be fully async instead of fire and forget
This commit is contained in:
Sheldan
2020-08-29 01:24:06 +02:00
parent fbb36ae9d5
commit 552ecc26b8
285 changed files with 1607 additions and 847 deletions

View File

@@ -3,8 +3,8 @@ package dev.sheldan.abstracto.core.command;
import dev.sheldan.abstracto.core.command.condition.ConditionResult;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.config.Parameters;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameter;
import dev.sheldan.abstracto.core.command.exception.ParameterTooLong;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterException;
import dev.sheldan.abstracto.core.command.exception.ParameterTooLongException;
import dev.sheldan.abstracto.core.command.service.CommandManager;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.ExceptionService;
@@ -200,7 +200,7 @@ public class CommandReceivedHandler extends ListenerAdapter {
}
String value = unParsedCommandParameter.getParameters().get(i);
if(param.getMaxLength() != null && (value.length() + Constants.PARAMETER_LIMIT) > param.getMaxLength()) {
throw new ParameterTooLong("The passed parameter was too long.", command, param.getName(), value.length(), param.getMaxLength());
throw new ParameterTooLongException(command, param.getName(), value.length(), param.getMaxLength());
}
try {
if(param.getType().equals(Integer.class)){
@@ -302,7 +302,7 @@ public class CommandReceivedHandler extends ListenerAdapter {
}
}
} catch (NoSuchElementException e) {
throw new IncorrectParameter(command, param.getType(), param.getName());
throw new IncorrectParameterException(command, param.getType(), param.getName());
} catch (IllegalArgumentException e) {
}

View File

@@ -2,8 +2,8 @@ package dev.sheldan.abstracto.core.command.service;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.config.ModuleInterface;
import dev.sheldan.abstracto.core.command.exception.CommandNotFound;
import dev.sheldan.abstracto.core.command.exception.InsufficientParameters;
import dev.sheldan.abstracto.core.command.exception.CommandNotFoundException;
import dev.sheldan.abstracto.core.command.exception.InsufficientParametersException;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.UnParsedCommandParameter;
@@ -11,7 +11,6 @@ import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
@@ -47,7 +46,7 @@ public class CommandManager implements CommandRegistry {
boolean hasRemainderParameter = commandConfiguration.getParameters().stream().anyMatch(Parameter::isRemainder);
if(unParsedCommandParameter.getParameters().size() < commandConfiguration.getNecessaryParameterCount()) {
String nextParameterName = commandConfiguration.getParameters().get(commandConfiguration.getNecessaryParameterCount() - 1).getName();
throw new InsufficientParameters(o, nextParameterName);
throw new InsufficientParametersException(o, nextParameterName);
}
parameterFit = paramCountFits || hasRemainderParameter;
} else {
@@ -58,7 +57,7 @@ public class CommandManager implements CommandRegistry {
if(commandOptional.isPresent()){
return commandOptional.get();
}
throw new CommandNotFound("Command not found.");
throw new CommandNotFoundException();
}
private boolean commandNameMatches(String name, CommandConfiguration commandConfiguration) {
@@ -81,7 +80,7 @@ public class CommandManager implements CommandRegistry {
if(commandOptional.isPresent()){
return commandOptional.get();
}
throw new CommandNotFound("Command not found.");
throw new CommandNotFoundException();
}
@Override

View File

@@ -26,6 +26,8 @@ import java.util.List;
@Slf4j
public class CommandServiceBean implements CommandService {
public static final String NO_FEATURE_COMMAND_FOUND_EXCEPTION_TEMPLATE = "no_feature_command_found_exception";
@Autowired
private ModuleManagementService moduleManagementService;

View File

@@ -5,10 +5,20 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.exception.GenericExceptionModel;
import dev.sheldan.abstracto.core.models.FullUser;
import dev.sheldan.abstracto.core.models.FullUserInServer;
import dev.sheldan.abstracto.core.models.database.AUser;
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.service.management.UserManagementService;
import dev.sheldan.abstracto.templating.Templatable;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.MessageChannel;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -16,37 +26,105 @@ import org.springframework.stereotype.Component;
@Slf4j
public class ExceptionServiceBean implements ExceptionService {
public static final String MODEL_WRAPPER_TEMPLATE_KEY = "model_wrapper";
@Autowired
private ChannelService channelService;
@Autowired
private TemplateService templateService;
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private UserManagementService userManagementService;
@Override
public CommandResult reportExceptionToContext(Throwable throwable, CommandContext context, Command command) {
if(command != null && command.getConfiguration().isReportsException()) {
if(command != null && command.getConfiguration().isSupportsEmbedException()) {
try {
FullUser fullUser = FullUser
.builder()
.aUserInAServer(context.getUserInitiatedContext().getAUserInAServer())
.member(context.getAuthor())
.build();
GenericExceptionModel modMailExceptionModel = GenericExceptionModel
.builder()
.user(fullUser)
.throwable(throwable)
.build();
channelService.sendEmbedTemplateInChannel("generic_command_exception", modMailExceptionModel, context.getChannel());
GenericExceptionModel exceptionModel = buildCommandModel(throwable, context);
channelService.sendEmbedTemplateInChannel("generic_command_exception", exceptionModel, context.getChannel());
} catch (Exception e) {
log.error("Failed to notify about assignable role exception.", e);
}
} else if(throwable instanceof Templatable){
Templatable exception = (Templatable) throwable;
String text = templateService.renderTemplate(exception.getTemplateName(), exception.getTemplateModel());
GenericExceptionModel exceptionModel = buildCommandModel(throwable, context);
String text = templateService.renderTemplate(MODEL_WRAPPER_TEMPLATE_KEY, exceptionModel);
channelService.sendTextToChannel(text, context.getChannel());
} else {
channelService.sendTextToChannel(throwable.getLocalizedMessage(), context.getChannel());
}
return CommandResult.fromReportedError();
}
@Override
public void reportExceptionToGuildMessageReceivedContext(Throwable exception, GuildMessageReceivedEvent event) {
if(exception instanceof Templatable){
GenericExceptionModel model = buildMemberContext(exception, event.getMember());
String text = templateService.renderTemplate(MODEL_WRAPPER_TEMPLATE_KEY, model);
channelService.sendTextToChannel(text, event.getChannel());
} else {
channelService.sendTextToChannel(exception.getLocalizedMessage(), event.getChannel());
}
}
@Override
public void reportExceptionToPrivateMessageReceivedContext(Throwable exception, PrivateMessageReceivedEvent event) {
if(exception instanceof Templatable){
GenericExceptionModel model = buildPrivateMessageReceivedModel(exception, event.getAuthor());
String text = templateService.renderTemplate(MODEL_WRAPPER_TEMPLATE_KEY, model);
channelService.sendTextToChannel(text, event.getChannel());
} else {
channelService.sendTextToChannel(exception.getLocalizedMessage(), event.getChannel());
}
}
@Override
public void reportExceptionToChannel(Throwable exception, MessageChannel channel, Member member) {
if(exception instanceof Templatable){
GenericExceptionModel model = buildMemberContext(exception, member);
String text = templateService.renderTemplate(MODEL_WRAPPER_TEMPLATE_KEY, model);
channelService.sendTextToChannel(text, channel);
} else {
channelService.sendTextToChannel(exception.getLocalizedMessage(), channel);
}
}
private GenericExceptionModel buildCommandModel(Throwable throwable, CommandContext context) {
FullUserInServer fullUser = FullUserInServer.builder().member(context.getAuthor()).aUserInAServer(context.getUserInitiatedContext().getAUserInAServer()).build();
return GenericExceptionModel
.builder()
.user(fullUser)
.throwable(throwable)
.build();
}
private GenericExceptionModel buildMemberContext(Throwable throwable, Member member) {
AUserInAServer userInAServer = userInServerManagementService.loadUser(member);
FullUserInServer fullUser = FullUserInServer
.builder()
.aUserInAServer(userInAServer)
.member(member)
.build();
return GenericExceptionModel
.builder()
.user(fullUser)
.throwable(throwable)
.build();
}
private GenericExceptionModel buildPrivateMessageReceivedModel(Throwable throwable, User user) {
AUser aUser = userManagementService.loadUser(user.getIdLong());
FullUser fullUser = FullUser
.builder()
.user(user)
.auser(aUser)
.build();
return GenericExceptionModel
.builder()
.fullUser(fullUser)
.throwable(throwable)
.build();
}
}

View File

@@ -48,7 +48,7 @@ public class CommandManagementServiceBean implements CommandManagementService {
@Override
public ACommand findCommandByName(String name) {
return findCommandByNameOptional(name).orElseThrow(() -> new CommandNotFoundException(String.format("Command %s was not found.", name)));
return findCommandByNameOptional(name).orElseThrow(CommandNotFoundException::new);
}
@Override

View File

@@ -43,6 +43,7 @@ public class AddToChannelGroup extends AbstractConditionableCommand {
.module(ChannelsModuleInterface.CHANNELS)
.aliases(aliases)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)

View File

@@ -39,6 +39,7 @@ public class CreateChannelGroup extends AbstractConditionableCommand {
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.aliases(aliases)
.supportsEmbedException(true)
.templated(true)
.help(helpInfo)
.causesReaction(true)

View File

@@ -39,6 +39,7 @@ public class DeleteChannelGroup extends AbstractConditionableCommand {
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.aliases(aliases)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)

View File

@@ -40,6 +40,7 @@ public class DisableCommand extends AbstractConditionableCommand {
.name("disableCommand")
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)

View File

@@ -40,6 +40,7 @@ public class EnableCommand extends AbstractConditionableCommand {
.name("enableCommand")
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.supportsEmbedException(true)
.templated(true)
.help(helpInfo)
.causesReaction(true)

View File

@@ -82,6 +82,7 @@ public class ListChannelGroups extends AbstractConditionableCommand {
.aliases(aliases)
.templated(true)
.help(helpInfo)
.supportsEmbedException(true)
.causesReaction(true)
.build();
}

View File

@@ -7,10 +7,10 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.*;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.command.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.exception.PostTargetNotValidException;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.PostTarget;
import dev.sheldan.abstracto.core.models.template.commands.PostTargetDisplayModel;
import dev.sheldan.abstracto.core.models.template.commands.PostTargetErrorModel;
import dev.sheldan.abstracto.core.models.template.commands.PostTargetModelEntry;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.PostTargetService;
@@ -33,7 +33,6 @@ import java.util.Optional;
public class PostTargetCommand extends AbstractConditionableCommand {
public static final String POST_TARGET_SHOW_TARGETS = "posttarget_show_targets";
public static final String POST_TARGET_INVALID_TARGET_TEMPLATE = "posttarget_invalid_target";
@Autowired
private PostTargetManagement postTargetManagement;
@@ -73,10 +72,7 @@ public class PostTargetCommand extends AbstractConditionableCommand {
}
String targetName = (String) commandContext.getParameters().getParameters().get(0);
if(!postTargetService.validPostTarget(targetName)) {
PostTargetErrorModel postTargetErrorModel = (PostTargetErrorModel) ContextConverter.fromCommandContext(commandContext, PostTargetErrorModel.class);
postTargetErrorModel.setValidPostTargets(postTargetService.getAvailablePostTargets());
String errorMessage = templateService.renderTemplate(POST_TARGET_INVALID_TARGET_TEMPLATE, postTargetErrorModel);
return CommandResult.fromError(errorMessage);
throw new PostTargetNotValidException(targetName, postTargetService.getAvailablePostTargets());
}
GuildChannel channel = (GuildChannel) commandContext.getParameters().getParameters().get(1);
Guild guild = channel.getGuild();
@@ -95,6 +91,7 @@ public class PostTargetCommand extends AbstractConditionableCommand {
.name("posttarget")
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)

View File

@@ -45,6 +45,7 @@ public class RemoveFromChannelGroup extends AbstractConditionableCommand {
.parameters(parameters)
.templated(true)
.help(helpInfo)
.supportsEmbedException(true)
.causesReaction(true)
.build();
}

View File

@@ -35,6 +35,7 @@ public class ClearCache extends AbstractConditionableCommand {
.name("clearCache")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)

View File

@@ -42,6 +42,7 @@ public class SetConfig extends AbstractConditionableCommand {
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.templated(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();

View File

@@ -37,6 +37,7 @@ public class SetPrefix extends AbstractConditionableCommand {
.name("setPrefix")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)

View File

@@ -10,6 +10,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.exception.FeatureNotFoundException;
import dev.sheldan.abstracto.core.interactive.InteractiveService;
import dev.sheldan.abstracto.core.models.AServerChannelUserId;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
@@ -19,6 +20,7 @@ import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class Setup extends AbstractConditionableCommand {
@@ -36,7 +38,7 @@ public class Setup extends AbstractConditionableCommand {
private SetupService setupService;
@Override
public CommandResult execute(CommandContext commandContext) {
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
String name = (String) commandContext.getParameters().getParameters().get(0);
if(featureManagementService.featureExists(name)) {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(name);
@@ -46,9 +48,10 @@ public class Setup extends AbstractConditionableCommand {
.channelId(commandContext.getChannel().getIdLong())
.userId(commandContext.getAuthor().getIdLong())
.build();
setupService.performSetup(feature, initiatingUser, commandContext.getMessage().getIdLong());
return setupService.performSetup(feature, initiatingUser, commandContext.getMessage().getIdLong())
.thenApply(aVoid -> CommandResult.fromSuccess());
}
return CommandResult.fromSuccess();
throw new FeatureNotFoundException(name, featureConfigService.getFeaturesAsList());
}
@Override
@@ -60,6 +63,8 @@ public class Setup extends AbstractConditionableCommand {
.name("setup")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.async(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
@@ -52,7 +53,7 @@ public class Allow extends AbstractConditionableCommand {
ACommand command = commandManagementService.findCommandByName(name);
commandService.unRestrictCommand(command, commandContext.getUserInitiatedContext().getServer());
} else {
return CommandResult.fromError(templateService.renderTemplate("no_feature_command_found", new Object()));
return CommandResult.fromError(templateService.renderTemplate(CommandServiceBean.NO_FEATURE_COMMAND_FOUND_EXCEPTION_TEMPLATE, new Object()));
}
return CommandResult.fromSuccess();
}

View File

@@ -9,6 +9,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
@@ -55,7 +56,7 @@ public class AllowRole extends AbstractConditionableCommand {
ACommand command = commandManagementService.findCommandByName(name);
commandService.allowCommandForRole(command, role);
} else {
return CommandResult.fromError(templateService.renderTemplate("no_feature_command_found", new Object()));
return CommandResult.fromError(templateService.renderTemplate(CommandServiceBean.NO_FEATURE_COMMAND_FOUND_EXCEPTION_TEMPLATE, new Object()));
}
return CommandResult.fromSuccess();
}

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
@@ -54,7 +55,7 @@ public class DisAllowRole extends AbstractConditionableCommand {
ACommand command = commandManagementService.findCommandByName(name);
commandService.disAllowCommandForRole(command, role);
} else {
return CommandResult.fromError(templateService.renderTemplate("no_feature_command_found", new Object()));
return CommandResult.fromError(templateService.renderTemplate(CommandServiceBean.NO_FEATURE_COMMAND_FOUND_EXCEPTION_TEMPLATE, new Object()));
}
return CommandResult.fromSuccess();
}

View File

@@ -70,6 +70,7 @@ public class Disable extends AbstractConditionableCommand {
.parameters(parameters)
.help(helpInfo)
.templated(true)
.supportsEmbedException(true)
.causesReaction(true)
.build();
}

View File

@@ -72,6 +72,7 @@ public class Enable extends AbstractConditionableCommand {
.name("enable")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.supportsEmbedException(true)
.templated(true)
.help(helpInfo)
.causesReaction(true)

View File

@@ -53,6 +53,7 @@ public class Features extends AbstractConditionableCommand {
.name("features")
.module(ConfigModuleInterface.CONFIG)
.templated(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)
.build();

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
@@ -54,7 +55,7 @@ public class MakeAffected extends AbstractConditionableCommand {
ACommand command = commandManagementService.findCommandByName(name);
commandService.makeRoleAffectedByCommand(command, role);
} else {
return CommandResult.fromError(templateService.renderTemplate("no_feature_command_found", new Object()));
return CommandResult.fromError(templateService.renderTemplate(CommandServiceBean.NO_FEATURE_COMMAND_FOUND_EXCEPTION_TEMPLATE, new Object()));
}
return CommandResult.fromSuccess();
}

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
@@ -54,7 +55,7 @@ public class MakeImmune extends AbstractConditionableCommand {
ACommand command = commandManagementService.findCommandByName(name);
commandService.makeRoleImmuneForCommand(command, role);
} else {
return CommandResult.fromError(templateService.renderTemplate("no_feature_command_found", new Object()));
return CommandResult.fromError(templateService.renderTemplate(CommandServiceBean.NO_FEATURE_COMMAND_FOUND_EXCEPTION_TEMPLATE, new Object()));
}
return CommandResult.fromSuccess();
}

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
@@ -52,7 +53,7 @@ public class Restrict extends AbstractConditionableCommand {
ACommand command = commandManagementService.findCommandByName(name);
commandService.restrictCommand(command, commandContext.getUserInitiatedContext().getServer());
} else {
return CommandResult.fromError(templateService.renderTemplate("no_feature_command_found", new Object()));
return CommandResult.fromError(templateService.renderTemplate(CommandServiceBean.NO_FEATURE_COMMAND_FOUND_EXCEPTION_TEMPLATE, new Object()));
}
return CommandResult.fromSuccess();
}

View File

@@ -45,6 +45,7 @@ public class Echo extends AbstractConditionableCommand {
.name("echo")
.module(UtilityModuleInterface.UTILITY)
.templated(true)
.supportsEmbedException(true)
.causesReaction(false)
.parameters(parameters)
.help(helpInfo)

View File

@@ -46,6 +46,7 @@ public class SetEmote extends AbstractConditionableCommand {
.name("setEmote")
.module(UtilityModuleInterface.UTILITY)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)

View File

@@ -4,8 +4,8 @@ import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.templating.Templatable;
public class NoChannelProvidedException extends AbstractoRunTimeException implements Templatable {
public NoChannelProvidedException(String message) {
super(message);
public NoChannelProvidedException() {
super("No channel was provided");
}
@Override

View File

@@ -81,7 +81,7 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep {
result = SetupStepResult.fromCancelled();
} else {
if(message.getMentionedChannels().size() == 0) {
throw new NoChannelProvidedException("No channel was provided.");
throw new NoChannelProvidedException();
}
TextChannel textChannel = message.getMentionedChannels().get(0);
PostTargetDelayedActionConfig build = PostTargetDelayedActionConfig

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.command.service.ExceptionService;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
@@ -37,6 +38,9 @@ public class MessageReceivedListenerBean extends ListenerAdapter {
@Autowired
private BotService botService;
@Autowired
private ExceptionService exceptionService;
@Override
public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) {
messageCache.putMessageInCache(event.getMessage());
@@ -49,6 +53,7 @@ public class MessageReceivedListenerBean extends ListenerAdapter {
messageReceivedListener.execute(event.getMessage());
} catch (Exception e) {
log.error("Listener {} had exception when executing.", messageReceivedListener, e);
exceptionService.reportExceptionToGuildMessageReceivedContext(e, event);
}
});
}
@@ -63,6 +68,7 @@ public class MessageReceivedListenerBean extends ListenerAdapter {
messageReceivedListener.execute(event.getMessage());
} catch (Exception e) {
log.error("Listener {} had exception when executing.", messageReceivedListener, e);
exceptionService.reportExceptionToPrivateMessageReceivedContext(e, event);
}
});
}

View File

@@ -1,6 +1,5 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.exception.CategoryNotFoundException;
import dev.sheldan.abstracto.core.exception.ChannelNotFoundException;
import dev.sheldan.abstracto.core.exception.GuildNotFoundException;
@@ -171,7 +170,7 @@ public class ChannelServiceBean implements ChannelService {
if(messageToSend.getEmbeds() != null && !messageToSend.getEmbeds().isEmpty()) {
messageAction = channel.editMessageById(messageId, messageToSend.getEmbeds().get(0));
} else {
throw new AbstractoRunTimeException("Message to send did not contain anything to send.");
throw new IllegalArgumentException("Message to send did not contain anything to send.");
}
}
return messageAction.submit();

View File

@@ -45,7 +45,7 @@ public class FeatureConfigServiceBean implements FeatureConfigService {
if(any.isPresent()) {
return any.get();
}
throw new FeatureNotFoundException("", featureEnum.getKey(), getFeaturesAsList());
throw new FeatureNotFoundException(featureEnum.getKey(), getFeaturesAsList());
}
@Override
@@ -83,7 +83,7 @@ public class FeatureConfigServiceBean implements FeatureConfigService {
if(foundFeature.isPresent()) {
return foundFeature.get().getFeature();
}
throw new FeatureNotFoundException("", key, getFeaturesAsList());
throw new FeatureNotFoundException(key, getFeaturesAsList());
}
@Override
@@ -121,7 +121,7 @@ public class FeatureConfigServiceBean implements FeatureConfigService {
if(foundFeature.isPresent()) {
return foundFeature.get();
}
throw new FeatureModeNotFoundException("", key, getFeatureModesFromFeatureAsString(featureConfig.getFeature().getKey()));
throw new FeatureModeNotFoundException(key, getFeatureModesFromFeatureAsString(featureConfig.getFeature().getKey()));
}
@Override

View File

@@ -47,7 +47,7 @@ public class FeatureFlagServiceBean implements FeatureFlagService {
public void enableFeature(FeatureConfig name, AServer server) {
FeatureEnum feature = name.getFeature();
if(!featureConfigService.doesFeatureExist(name)) {
throw new FeatureNotFoundException("Feature not found.", feature.getKey(), featureConfigService.getFeaturesAsList());
throw new FeatureNotFoundException(feature.getKey(), featureConfigService.getFeaturesAsList());
}
updateFeatureFlag(feature, server, true);
}
@@ -62,7 +62,7 @@ public class FeatureFlagServiceBean implements FeatureFlagService {
public void disableFeature(FeatureConfig name, AServer server) {
FeatureEnum feature = name.getFeature();
if(!featureConfigService.doesFeatureExist(name)) {
throw new FeatureNotFoundException("Feature not found.", feature.getKey(), featureConfigService.getFeaturesAsList());
throw new FeatureNotFoundException(feature.getKey(), featureConfigService.getFeaturesAsList());
}
updateFeatureFlag(feature, server, false);
}

View File

@@ -1,7 +1,7 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.exception.EmoteNotDefinedException;
import dev.sheldan.abstracto.core.exception.ExceptionNotInServerException;
import dev.sheldan.abstracto.core.exception.ConfiguredEmoteNotUsableException;
import dev.sheldan.abstracto.core.exception.EmoteNotInServerException;
import dev.sheldan.abstracto.core.exception.GuildNotFoundException;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
@@ -55,7 +55,7 @@ public class MessageServiceBean implements MessageService {
return message.addReaction(emoteById).submit();
} else {
log.error("Emote with key {} and id {} for guild {} was not found.", emoteKey, emote.getEmoteId(), guild.getId());
throw new EmoteNotDefinedException(emoteKey);
throw new ConfiguredEmoteNotUsableException(emote);
}
} else {
return message.addReaction(emote.getEmoteKey()).submit();
@@ -79,7 +79,7 @@ public class MessageServiceBean implements MessageService {
public CompletableFuture<Void> addReactionToMessageWithFuture(Long emoteId, Long serverId, Message message) {
Emote emoteById = botService.getInstance().getEmoteById(emoteId);
if(emoteById == null) {
throw new ExceptionNotInServerException(emoteId);
throw new EmoteNotInServerException(emoteId);
}
return message.addReaction(emoteById).submit();
}
@@ -89,7 +89,7 @@ public class MessageServiceBean implements MessageService {
if(Boolean.TRUE.equals(emote.getCustom())) {
Emote emoteById = botService.getInstance().getEmoteById(emote.getEmoteId());
if(emoteById == null) {
throw new ExceptionNotInServerException(emote.getEmoteId());
throw new EmoteNotInServerException(emote.getEmoteId());
}
return message.removeReaction(emoteById).submit();
} else {
@@ -102,7 +102,7 @@ public class MessageServiceBean implements MessageService {
if(Boolean.TRUE.equals(emote.getCustom())) {
Emote emoteById = botService.getInstance().getEmoteById(emote.getEmoteId());
if(emoteById == null) {
throw new ExceptionNotInServerException(emote.getEmoteId());
throw new EmoteNotInServerException(emote.getEmoteId());
}
return message.clearReactions(emoteById).submit();
} else {
@@ -150,7 +150,7 @@ public class MessageServiceBean implements MessageService {
if(Boolean.TRUE.equals(emote.getCustom())) {
Emote emoteById = botService.getInstance().getEmoteById(emote.getEmoteId());
if(emoteById == null) {
throw new ExceptionNotInServerException(emote.getEmoteId());
throw new EmoteNotInServerException(emote.getEmoteId());
}
return message.removeReaction(emoteById, member.getUser()).submit();
} else {

View File

@@ -1,14 +1,16 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.command.service.ExceptionService;
import dev.sheldan.abstracto.core.exception.ChannelNotFoundException;
import dev.sheldan.abstracto.core.interactive.DelayedActionConfig;
import dev.sheldan.abstracto.core.config.FeatureConfig;
import dev.sheldan.abstracto.core.interactive.*;
import dev.sheldan.abstracto.core.models.AServerChannelUserId;
import dev.sheldan.abstracto.core.models.template.commands.SetupCompletedNotificationModel;
import dev.sheldan.abstracto.core.models.template.commands.SetupInitialMessageModel;
import dev.sheldan.abstracto.templating.Templatable;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -17,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
@@ -46,8 +49,11 @@ public class SetupServiceBean implements SetupService {
@Autowired
private BotService botService;
@Autowired
private ExceptionService exceptionService;
@Override
public void performSetup(FeatureConfig featureConfig, AServerChannelUserId user, Long initialMessageId) {
public CompletableFuture<Void> performSetup(FeatureConfig featureConfig, AServerChannelUserId user, Long initialMessageId) {
List<String> requiredSystemConfigKeys = featureConfig.getRequiredSystemConfigKeys();
List<SetupExecution> steps = new ArrayList<>();
requiredSystemConfigKeys.forEach(s -> {
@@ -87,21 +93,23 @@ public class SetupServiceBean implements SetupService {
.featureConfig(featureConfig)
.build();
Optional<TextChannel> textChannelInGuild = channelService.getTextChannelInGuild(user.getGuildId(), user.getChannelId());
textChannelInGuild.ifPresent(textChannel -> {
if(textChannelInGuild.isPresent()) {
TextChannel textChannel = textChannelInGuild.get();
String text = templateService.renderTemplate("setup_initial_message", setupInitialMessageModel);
channelService.sendTextToChannel(text, textChannel);
executeSetup(featureConfig, steps, user, new ArrayList<>());
});
return executeSetup(featureConfig, steps, user, new ArrayList<>());
}
throw new ChannelNotFoundException(user.getChannelId());
}
@Override
public void executeSetup(FeatureConfig featureConfig, List<SetupExecution> steps, AServerChannelUserId user, List<DelayedActionConfig> delayedActionConfigs) {
steps.stream().findFirst().ifPresent(execution -> executeStep(user, execution, delayedActionConfigs, featureConfig));
public CompletableFuture<Void> executeSetup(FeatureConfig featureConfig, List<SetupExecution> steps, AServerChannelUserId user, List<DelayedActionConfig> delayedActionConfigs) {
SetupExecution nextStep = steps.get(0);
return executeStep(user, nextStep, delayedActionConfigs, featureConfig);
}
private void executeStep(AServerChannelUserId aUserInAServer, SetupExecution execution, List<DelayedActionConfig> delayedActionConfigs, FeatureConfig featureConfig) {
execution.getStep().execute(aUserInAServer, execution.getParameter()).thenAccept(aVoid -> {
private CompletableFuture<Void> executeStep(AServerChannelUserId aUserInAServer, SetupExecution execution, List<DelayedActionConfig> delayedActionConfigs, FeatureConfig featureConfig) {
return execution.getStep().execute(aUserInAServer, execution.getParameter()).thenAccept(aVoid -> {
if(aVoid.getResult().equals(SetupStepResultType.SUCCESS)) {
delayedActionConfigs.addAll(aVoid.getDelayedActionConfigList());
if(execution.getNextStep() != null) {
@@ -122,12 +130,9 @@ public class SetupServiceBean implements SetupService {
@Transactional
public void showExceptionMessage(Throwable throwable, AServerChannelUserId aServerChannelUserId) {
if(throwable instanceof Templatable) {
Templatable exception = (Templatable) throwable;
String text = templateService.renderTemplate(exception.getTemplateName(), exception.getTemplateModel());
Optional<TextChannel> channelOptional = botService.getTextChannelFromServerOptional(aServerChannelUserId.getGuildId(), aServerChannelUserId.getChannelId());
channelOptional.ifPresent(channel -> channelService.sendTextToChannel(text, channel));
}
Optional<TextChannel> channelOptional = botService.getTextChannelFromServerOptional(aServerChannelUserId.getGuildId(), aServerChannelUserId.getChannelId());
Member member = botService.getMemberInServer(aServerChannelUserId.getGuildId(), aServerChannelUserId.getUserId());
channelOptional.ifPresent(textChannel -> exceptionService.reportExceptionToChannel(throwable, textChannel, member));
}
@Transactional

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.models.FullUser;
import dev.sheldan.abstracto.core.models.FullUserInServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.UserInServerService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -13,8 +13,8 @@ public class UserInServerServiceBean implements UserInServerService {
private BotService botService;
@Override
public FullUser getFullUser(AUserInAServer aUserInAServer) {
return FullUser
public FullUserInServer getFullUser(AUserInAServer aUserInAServer) {
return FullUserInServer
.builder()
.member(botService.getMemberInServer(aUserInAServer))
.aUserInAServer(aUserInAServer)

View File

@@ -1,7 +1,9 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.command.exception.ChannelAlreadyInChannelGroupException;
import dev.sheldan.abstracto.core.command.exception.ChannelGroupExistsException;
import dev.sheldan.abstracto.core.command.exception.ChannelGroupNotFoundException;
import dev.sheldan.abstracto.core.command.exception.ChannelNotInChannelGroupException;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
@@ -56,7 +58,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
public AChannelGroup addChannelToChannelGroup(AChannelGroup channelGroup, AChannel channel) {
Predicate<AChannel> channelInGroupPredicate = channel1 -> channel1.getId().equals(channel.getId());
if(channelGroup.getChannels().stream().anyMatch(channelInGroupPredicate)) {
throw new ChannelGroupExistsException(String.format("Channel %s is already part of group %s.", channel.getId(), channelGroup.getGroupName()));
throw new ChannelAlreadyInChannelGroupException(channel, channelGroup);
}
channelGroup.getChannels().add(channel);
channel.getGroups().add(channelGroup);
@@ -67,7 +69,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
public void removeChannelFromChannelGroup(AChannelGroup channelGroup, AChannel channel) {
Predicate<AChannel> channelInGroupPredicate = channel1 -> channel1.getId().equals(channel.getId());
if(channelGroup.getChannels().stream().noneMatch(channelInGroupPredicate)) {
throw new ChannelGroupExistsException(String.format("Channel %s is not part of group %s.", channel.getId(), channelGroup.getGroupName()));
throw new ChannelNotInChannelGroupException(channel, channelGroup);
}
channelGroup.getChannels().removeIf(channelInGroupPredicate);
channel.getGroups().removeIf(channelGroup1 -> channelGroup1.getId().equals(channelGroup.getId()));