[AB-138] improving logging at various places fixing various issues regarding async commands and exception handling, fixing role role calculation being done twice

This commit is contained in:
Sheldan
2020-10-07 09:29:56 +02:00
parent a391381ff6
commit 0145e7670d
165 changed files with 1129 additions and 513 deletions

View File

@@ -103,26 +103,29 @@ public class CommandReceivedHandler extends ListenerAdapter {
UnParsedCommandParameter unParsedParameter = new UnParsedCommandParameter(contentStripped);
String commandName = commandManager.getCommandName(parameters.get(0), event.getGuild().getIdLong());
foundCommand = commandManager.findCommandByParameters(commandName, unParsedParameter);
tryToExecuteFoundCommand(event, userInitiatedContext, commandContextBuilder, foundCommand, unParsedParameter);
tryToExecuteFoundCommand(event, commandContextBuilder, foundCommand, unParsedParameter);
} catch (Exception e) {
log.error("Exception when preparing command.", e);
log.error("Exception when executing command.", e);
CommandResult commandResult = CommandResult.fromError(e.getMessage(), e);
CommandContext commandContext = commandContextBuilder.build();
self.executePostCommandListener(null, commandContext, commandResult);
}
}
private void tryToExecuteFoundCommand(@Nonnull MessageReceivedEvent event, UserInitiatedServerContext userInitiatedContext, CommandContext.CommandContextBuilder commandContextBuilder, Command foundCommand, UnParsedCommandParameter unParsedParameter) {
private void tryToExecuteFoundCommand(@Nonnull MessageReceivedEvent event, CommandContext.CommandContextBuilder commandContextBuilder, Command foundCommand, UnParsedCommandParameter unParsedParameter) {
try {
Parameters parsedParameters = getParsedParameters(unParsedParameter, foundCommand, event.getMessage(), userInitiatedContext);
Parameters parsedParameters = getParsedParameters(unParsedParameter, foundCommand, event.getMessage());
validateCommandParameters(parsedParameters, foundCommand);
CommandContext commandContext = commandContextBuilder.parameters(parsedParameters).build();
ConditionResult conditionResult = commandService.isCommandExecutable(foundCommand, commandContext);
CommandResult commandResult = null;
if(conditionResult.isResult()) {
if(foundCommand.getConfiguration().isAsync()) {
foundCommand.executeAsync(commandContext).thenAccept(result ->
if(foundCommand.getConfiguration().isAsync()) {
log.info("Executing async command {} for server {} in channel {} based on message {} by user {}.",
foundCommand.getConfiguration().getName(), commandContext.getGuild().getId(), commandContext.getChannel().getId(), commandContext.getMessage().getId(), commandContext.getAuthor().getId());
foundCommand.executeAsync(commandContext).thenAccept(result ->
executePostCommandListener(foundCommand, commandContext, result)
).exceptionally(throwable -> {
log.error("Asynchronous command {} failed.", foundCommand.getConfiguration().getName(), throwable);
@@ -169,6 +172,7 @@ public class CommandReceivedHandler extends ListenerAdapter {
for (ParameterValidator parameterValidator : parameter.getValidators()) {
boolean validate = parameterValidator.validate(parameters.getParameters().get(i));
if(!validate) {
log.trace("Parameter {} in command {} failed to validate.", parameter.getName(), foundCommand.getConfiguration().getName());
throw new CommandParameterValidationException(parameterValidator.getParameters(), parameterValidator.getTemplateName(), parameter);
}
}
@@ -177,6 +181,7 @@ public class CommandReceivedHandler extends ListenerAdapter {
@Transactional
public void executePostCommandListener(Command foundCommand, CommandContext commandContext, CommandResult result) {
log.trace("Executing post command listeners for command from message {}.", commandContext.getMessage().getIdLong());
for (PostCommandExecution postCommandExecution : executions) {
postCommandExecution.execute(commandContext, result, foundCommand);
}
@@ -184,6 +189,8 @@ public class CommandReceivedHandler extends ListenerAdapter {
@Transactional
public CommandResult executeCommand(Command foundCommand, CommandContext commandContext) {
log.info("Executing sync command {} for server {} in channel {} based on message {} by user {}.",
foundCommand.getConfiguration().getName(), commandContext.getGuild().getId(), commandContext.getChannel().getId(), commandContext.getMessage().getId(), commandContext.getAuthor().getId());
return foundCommand.execute(commandContext);
}
@@ -203,11 +210,12 @@ public class CommandReceivedHandler extends ListenerAdapter {
.build();
}
public Parameters getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message, UserInitiatedServerContext userInitiatedServerContext){
public Parameters getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message){
List<Object> parsedParameters = new ArrayList<>();
if(command.getConfiguration().getParameters() == null || command.getConfiguration().getParameters().isEmpty()) {
return Parameters.builder().parameters(parsedParameters).build();
}
log.trace("Parsing parameters for command {} based on message {}.", command.getConfiguration().getName(), message.getId());
Iterator<TextChannel> channelIterator = message.getMentionedChannels().iterator();
Iterator<Emote> emoteIterator = message.getEmotesBag().iterator();
Iterator<Member> memberIterator = message.getMentionedMembers().iterator();

View File

@@ -6,12 +6,14 @@ import dev.sheldan.abstracto.core.command.service.management.CommandInServerMana
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.listener.ServerConfigListener;
import dev.sheldan.abstracto.core.models.database.AServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class CommandConfigListener implements ServerConfigListener {
@Autowired
@@ -25,6 +27,7 @@ public class CommandConfigListener implements ServerConfigListener {
@Override
public void updateServerConfig(AServer server) {
log.info("Creating command instances for server {}.", server.getId());
commandList.forEach(command -> {
if(command.getConfiguration() != null) {
ACommand aCommand = commandManagementService.findCommandByName(command.getConfiguration().getName());

View File

@@ -5,14 +5,20 @@ 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.command.service.PostCommandExecution;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class SelfDestructPostExecution implements PostCommandExecution {
@Override
public void execute(CommandContext commandContext, CommandResult commandResult, Command command) {
if(commandResult.getResult().equals(ResultState.SELF_DESTRUCT)) {
commandContext.getMessage().delete().queue();
Message message = commandContext.getMessage();
log.trace("Command {} is of type self destruct. Deleting message {} in channel {} in server {}.",
command.getConfiguration().getName(), message.getId(), message.getChannel().getId(), message.getGuild().getId());
message.delete().queue();
}
}
}

View File

@@ -21,6 +21,7 @@ public class UndoActionPostExecution implements PostCommandExecution {
public void execute(CommandContext commandContext, CommandResult commandResult, Command command) {
ResultState result = commandResult.getResult();
if(result.equals(ResultState.ERROR) && commandContext.getUndoActions() != null && !commandContext.getUndoActions().isEmpty()) {
log.info("Performing undo cations for command {} in server {}.", command.getConfiguration().getName(), commandContext.getGuild().getIdLong());
undoActionService.performActionsFuture(commandContext.getUndoActions()).whenComplete((aVoid, undoThrowable) -> {
if(undoThrowable != null) {
log.warn("Undo actions failed.", undoThrowable);

View File

@@ -8,11 +8,12 @@ import org.springframework.data.jpa.repository.QueryHints;
import javax.persistence.QueryHint;
import java.util.List;
import java.util.Optional;
public interface ChannelGroupCommandRepository extends JpaRepository<AChannelGroupCommand, Long> {
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
AChannelGroupCommand findByCommandAndGroup(ACommand command, AChannelGroup group);
Optional<AChannelGroupCommand> findByCommandAndGroup(ACommand command, AChannelGroup group);
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
List<AChannelGroupCommand> findByCommand(ACommand command);

View File

@@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.management.ChannelGroupCommandManagementService;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -11,6 +12,7 @@ import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class ChannelGroupCommandServiceBean implements ChannelGroupCommandService {
@Autowired
@@ -23,9 +25,12 @@ public class ChannelGroupCommandServiceBean implements ChannelGroupCommandServic
Optional<AChannel> channelInGroup = aChannelGroupCommand.getGroup()
.getChannels().stream().filter(channel1 -> channel1.getId().equals(channel.getId())).findAny();
if (channelInGroup.isPresent() && aChannelGroupCommand.getEnabled()) {
log.trace("Command {} is enabled because the channel is part of group {} in server.", command.getName(), aChannelGroupCommand.getGroup().getId());
return true;
}
}
// empty -> no groups, command enabled
// not empty -> has groups, command is disabled in all
return allChannelGroupsOfCommand.isEmpty();
}
}

View File

@@ -73,14 +73,10 @@ public class CommandManager implements CommandRegistry {
}
public Command findCommand(String name) {
Optional<Command> commandOptional = commands.stream().filter((Command o )-> {
return commands.stream().filter((Command o )-> {
CommandConfiguration commandConfiguration = o.getConfiguration();
return commandConfiguration.getName().equals(name);
}).findFirst();
if(commandOptional.isPresent()){
return commandOptional.get();
}
throw new CommandNotFoundException();
}).findFirst().orElseThrow(CommandNotFoundException::new);
}
@Override
@@ -102,7 +98,7 @@ public class CommandManager implements CommandRegistry {
@Override
public boolean isCommand(Message message) {
return message.getContentRaw().startsWith(configService.getStringValue(PREFIX, message.getGuild().getIdLong(), defaultConfigManagementService.getDefaultConfig(PREFIX).getStringValue()));
return message.getContentRaw().startsWith(configService.getStringValue(PREFIX, message.getGuild().getIdLong(), getDefaultPrefix()));
}
@Override
@@ -117,6 +113,10 @@ public class CommandManager implements CommandRegistry {
@Override
public String getCommandName(String input, Long serverId) {
return input.replaceFirst(configService.getStringValue(PREFIX, serverId, defaultConfigManagementService.getDefaultConfig(PREFIX).getStringValue()), "");
return input.replaceFirst(configService.getStringValue(PREFIX, serverId, getDefaultPrefix()), "");
}
private String getDefaultPrefix() {
return defaultConfigManagementService.getDefaultConfig(PREFIX).getStringValue();
}
}

View File

@@ -66,6 +66,7 @@ public class CommandServiceBean implements CommandService {
if(commandForServer.getAllowedRoles().stream().noneMatch(role1 -> role1.getId().equals(role.getId()))) {
commandForServer.getAllowedRoles().add(role);
}
log.info("Allowing command {} for role {} in server {}.", aCommand.getName(), role.getId(), role.getServer().getId());
commandForServer.setRestricted(true);
}
@@ -73,6 +74,7 @@ public class CommandServiceBean implements CommandService {
public void allowFeatureForRole(FeatureEnum featureEnum, ARole role) {
AFeature feature = featureManagementService.getFeature(featureEnum.getKey());
feature.getCommands().forEach(command -> this.allowCommandForRole(command, role));
log.info("Allowing feature {} for role {} in server {}.", feature.getKey(), role.getId(), role.getServer().getId());
}
@Override
@@ -81,18 +83,21 @@ public class CommandServiceBean implements CommandService {
if(commandForServer.getImmuneRoles().stream().noneMatch(role1 -> role1.getId().equals(role.getId()))) {
commandForServer.getImmuneRoles().add(role);
}
log.info("Making role {} immune from command {} in server {}.", role.getId(), aCommand.getName(), role.getServer().getId());
}
@Override
public void makeRoleAffectedByCommand(ACommand aCommand, ARole role) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer());
commandForServer.getImmuneRoles().removeIf(role1 -> role1.getId().equals(role.getId()));
log.info("Making role {} affected from command {} in server {}.", role.getId(), aCommand.getName(), role.getServer().getId());
}
@Override
public void restrictCommand(ACommand aCommand, AServer server) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, server);
commandForServer.setRestricted(true);
log.info("Restricting command {} in server {}.", aCommand.getName(), server.getId());
}
@Override
@@ -119,6 +124,7 @@ public class CommandServiceBean implements CommandService {
public void unRestrictCommand(ACommand aCommand, AServer server) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, server);
commandForServer.setRestricted(false);
log.info("Removing restriction on command {} in server {}.", aCommand.getName(), server.getId());
}
@Override
@@ -126,12 +132,14 @@ public class CommandServiceBean implements CommandService {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer());
commandForServer.setRestricted(true);
commandForServer.getAllowedRoles().removeIf(role1 -> role1.getId().equals(role.getId()));
log.info("Disallowing command {} for role {} in server {}.", aCommand.getName(), role.getId(), role.getServer().getId());
}
@Override
public void disAllowFeatureForRole(FeatureEnum featureEnum, ARole role) {
AFeature feature = featureManagementService.getFeature(featureEnum.getKey());
feature.getCommands().forEach(command -> this.disAllowCommandForRole(command, role));
log.info("Disallowing feature {} for role {} in server {}.", feature.getKey(), role.getId(), role.getServer().getId());
}
public ConditionResult isCommandExecutable(Command command, CommandContext commandContext) {

View File

@@ -44,9 +44,11 @@ public class ExceptionServiceBean implements ExceptionService {
if(command != null && command.getConfiguration().isSupportsEmbedException()) {
try {
GenericExceptionModel exceptionModel = buildCommandModel(throwable, context);
log.info("Reporting generic exception {} of command {} towards channel {} in server {}.",
throwable.getClass().getSimpleName(), command.getConfiguration().getName(), context.getChannel().getId(), context.getGuild().getId());
channelService.sendEmbedTemplateInChannel("generic_command_exception", exceptionModel, context.getChannel());
} catch (Exception e) {
log.error("Failed to notify about assignable role exception.", e);
log.error("Failed to notify about exception.", e);
}
} else if(throwable instanceof Templatable){
GenericExceptionModel exceptionModel = buildCommandModel(throwable, context);

View File

@@ -2,14 +2,18 @@ package dev.sheldan.abstracto.core.command.service.management;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.repository.ChannelGroupCommandRepository;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCommandManagementService {
@Autowired
@@ -17,16 +21,16 @@ public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCom
@Override
public void setCommandInGroupTo(ACommand command, AChannelGroup group, Boolean enabled) {
AChannelGroupCommand groupCommand = groupCommandRepository.findByCommandAndGroup(command, group);
if(groupCommand == null) {
groupCommand = createCommandInGroupTo(command, group);
}
Optional<AChannelGroupCommand> groupCommandOptional = groupCommandRepository.findByCommandAndGroup(command, group);
AChannelGroupCommand groupCommand = groupCommandOptional.orElseGet(() -> createCommandInGroup(command, group));
groupCommand.setEnabled(enabled);
log.trace("Setting command {} enabled in group {} to {}.", command.getName(), group.getId(), enabled);
groupCommandRepository.save(groupCommand);
}
@Override
public AChannelGroupCommand createCommandInGroupTo(ACommand command, AChannelGroup group) {
public AChannelGroupCommand createCommandInGroup(ACommand command, AChannelGroup group) {
AChannelGroupCommand channelGroupCommand = AChannelGroupCommand
.builder()
.command(command)
@@ -34,13 +38,15 @@ public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCom
.enabled(false)
.build();
log.info("Creating command {} in group {}.", command.getName(), group.getId());
groupCommandRepository.save(channelGroupCommand);
return channelGroupCommand;
}
@Override
public AChannelGroupCommand getChannelGroupCommand(ACommand command, AChannelGroup group) {
return groupCommandRepository.findByCommandAndGroup(command, group);
return groupCommandRepository.findByCommandAndGroup(command, group).orElseThrow(() -> new AbstractoRunTimeException("Command not found in group."));
}
@Override

View File

@@ -4,10 +4,12 @@ import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.models.database.ACommandInAServer;
import dev.sheldan.abstracto.core.command.repository.CommandInServerRepository;
import dev.sheldan.abstracto.core.models.database.AServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class CommandInServerManagementServiceBean implements CommandInServerManagementService {
@Autowired
@@ -22,6 +24,7 @@ public class CommandInServerManagementServiceBean implements CommandInServerMana
.restricted(false)
.build();
repository.save(commandInAServer);
log.info("Creating command {} in server {}.", command.getName(), server.getId());
return commandInAServer;
}

View File

@@ -5,12 +5,14 @@ import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.models.database.AModule;
import dev.sheldan.abstracto.core.command.repository.CommandRepository;
import dev.sheldan.abstracto.core.models.database.AFeature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class CommandManagementServiceBean implements CommandManagementService {
@Autowired
@@ -37,6 +39,7 @@ public class CommandManagementServiceBean implements CommandManagementService {
.module(module)
.feature(feature)
.build();
log.info("Creating creating command {} in module {} with feature {}.", name, module.getName(), feature.getKey());
commandRepository.save(command);
return command;
}

View File

@@ -2,10 +2,12 @@ package dev.sheldan.abstracto.core.command.service.management;
import dev.sheldan.abstracto.core.command.models.database.AModule;
import dev.sheldan.abstracto.core.command.repository.ModuleRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class ModuleManagementServiceBean implements ModuleManagementService {
@Autowired
@@ -18,6 +20,7 @@ public class ModuleManagementServiceBean implements ModuleManagementService {
.name(name)
.build();
moduleRepository.save(module);
log.info("Creating module {}.", name);
return module;
}

View File

@@ -51,6 +51,7 @@ public class PostTargetCommand extends AbstractConditionableCommand {
@Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
if(commandContext.getParameters().getParameters().isEmpty()) {
log.trace("Displaying existing post targets for guild {}.", commandContext.getGuild().getId());
PostTargetDisplayModel posttargetDisplayModel = (PostTargetDisplayModel) ContextConverter.fromCommandContext(commandContext, PostTargetDisplayModel.class);
AServer server = commandContext.getUserInitiatedContext().getServer();
List<PostTarget> postTargets = postTargetService.getPostTargets(server);
@@ -79,7 +80,6 @@ public class PostTargetCommand extends AbstractConditionableCommand {
GuildChannel channel = (GuildChannel) commandContext.getParameters().getParameters().get(1);
Guild guild = channel.getGuild();
postTargetManagement.createOrUpdate(targetName, guild.getIdLong(), channel.getIdLong());
log.info("Setting posttarget {} in {} to {}", targetName, guild.getIdLong(), channel.getId());
return CompletableFuture.completedFuture(CommandResult.fromSuccess());
}

View File

@@ -18,6 +18,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -26,6 +27,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class Enable extends AbstractConditionableCommand {
@Autowired
@@ -53,11 +55,13 @@ public class Enable extends AbstractConditionableCommand {
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(flagKey);
FeatureValidationResult featureSetup = featureConfigService.validateFeatureSetup(feature, commandContext.getUserInitiatedContext().getServer());
if(Boolean.FALSE.equals(featureSetup.getValidationResult())) {
log.info("Feature {} has failed the setup validation. Notifying user.", flagKey);
channelService.sendTextToChannelNotAsync(templateService.renderTemplatable(featureSetup), commandContext.getChannel());
}
featureFlagService.enableFeature(feature, commandContext.getUserInitiatedContext().getServer());
if(feature.getRequiredFeatures() != null) {
feature.getRequiredFeatures().forEach(featureDisplay -> {
log.info("Also enabling required feature {}.", featureDisplay.getFeature().getKey());
featureFlagService.enableFeature(featureDisplay, commandContext.getUserInitiatedContext().getServer());
});
}

View File

@@ -14,12 +14,14 @@ import dev.sheldan.abstracto.core.models.database.AFeatureFlag;
import dev.sheldan.abstracto.core.models.template.commands.FeaturesModel;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.FeatureFlagManagementService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
public class Features extends AbstractConditionableCommand {
@@ -37,13 +39,13 @@ public class Features extends AbstractConditionableCommand {
private FeatureFlagConverter featureFlagConverter;
@Override
public CommandResult execute(CommandContext commandContext) {
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<AFeatureFlag> features = featureFlagManagementService.getFeatureFlagsOfServer(commandContext.getUserInitiatedContext().getServer());
FeaturesModel featuresModel = (FeaturesModel) ContextConverter.fromCommandContext(commandContext, FeaturesModel.class);
featuresModel.setFeatures(featureFlagConverter.fromFeatureFlags(features));
MessageToSend messageToSend = templateService.renderEmbedTemplate("features_response", featuresModel);
channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel());
return CommandResult.fromSuccess();
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override
@@ -53,6 +55,7 @@ public class Features extends AbstractConditionableCommand {
.name("features")
.module(ConfigModuleInterface.CONFIG)
.templated(true)
.async(true)
.supportsEmbedException(true)
.help(helpInfo)
.causesReaction(true)

View File

@@ -17,17 +17,21 @@ import dev.sheldan.abstracto.core.models.template.commands.help.HelpModuleDetail
import dev.sheldan.abstracto.core.models.template.commands.help.HelpModuleOverviewModel;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Service
@Slf4j
public class Help implements Command {
@@ -56,19 +60,15 @@ public class Help implements Command {
private CommandService commandService;
@Override
public CommandResult execute(CommandContext commandContext) {
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
if(parameters.isEmpty()) {
ModuleInterface moduleInterface = moduleService.getDefaultModule();
List<ModuleInterface> subModules = moduleService.getSubModules(moduleInterface);
HelpModuleOverviewModel model = (HelpModuleOverviewModel) ContextConverter.fromCommandContext(commandContext, HelpModuleOverviewModel.class);
model.setModules(subModules);
MessageToSend messageToSend = templateService.renderEmbedTemplate("help_module_overview_response", model);
channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel());
return displayHelpOverview(commandContext);
} else {
String parameter = (String) parameters.get(0);
if(moduleService.moduleExists(parameter)){
ModuleInterface moduleInterface = moduleService.getModuleByName(parameter);
log.trace("Displaying help for module {}.", moduleInterface.getInfo().getName());
SingleLevelPackedModule module = moduleService.getPackedModule(moduleInterface);
List<Command> commands = module.getCommands();
List<Command> filteredCommands = new ArrayList<>();
@@ -83,9 +83,11 @@ public class Help implements Command {
model.setModule(module);
model.setSubModules(subModules);
MessageToSend messageToSend = templateService.renderEmbedTemplate("help_module_details_response", model);
channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel());
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess());
} else if(commandRegistry.commandExists(parameter)) {
Command command = commandRegistry.getCommandByName(parameter);
log.trace("Displaying help for command {}.", command.getConfiguration().getName());
ACommand aCommand = commandManagementService.findCommandByName(parameter);
ACommandInAServer aCommandInAServer = commandInServerManagementService.getCommandForServer(aCommand, commandContext.getUserInitiatedContext().getServer());
HelpCommandDetailsModel model = (HelpCommandDetailsModel) ContextConverter.fromCommandContext(commandContext, HelpCommandDetailsModel.class);
@@ -97,10 +99,23 @@ public class Help implements Command {
model.setUsage(commandService.generateUsage(command));
model.setCommand(command.getConfiguration());
MessageToSend messageToSend = templateService.renderEmbedTemplate("help_command_details_response", model);
channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel());
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess());
} else {
return displayHelpOverview(commandContext);
}
}
return CommandResult.fromSuccess();
}
private CompletableFuture<CommandResult> displayHelpOverview(CommandContext commandContext) {
log.trace("Displaying help overview response.");
ModuleInterface moduleInterface = moduleService.getDefaultModule();
List<ModuleInterface> subModules = moduleService.getSubModules(moduleInterface);
HelpModuleOverviewModel model = (HelpModuleOverviewModel) ContextConverter.fromCommandContext(commandContext, HelpModuleOverviewModel.class);
model.setModules(subModules);
MessageToSend messageToSend = templateService.renderEmbedTemplate("help_module_overview_response", model);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess());
}
@Override
@@ -114,6 +129,7 @@ public class Help implements Command {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("help")
.async(true)
.module(SupportModuleInterface.SUPPORT)
.parameters(Collections.singletonList(moduleOrCommandName))
.help(helpInfo)

View File

@@ -1,10 +1,12 @@
package dev.sheldan.abstracto.core.interactive;
import dev.sheldan.abstracto.core.service.management.PostTargetManagement;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class PostTargetDelayedAction implements DelayedAction {
@Autowired
@@ -12,8 +14,9 @@ public class PostTargetDelayedAction implements DelayedAction {
@Override
public void execute(DelayedActionConfig delayedActionConfig) {
PostTargetDelayedActionConfig concrete = (PostTargetDelayedActionConfig) delayedActionConfig;
postTargetManagement.createOrUpdate(concrete.getPostTargetKey(), concrete.getServerId(), concrete.getChannelId());
PostTargetDelayedActionConfig castedConfig = (PostTargetDelayedActionConfig) delayedActionConfig;
log.trace("Executing post target delayed step to set post target {} to channel {} in server {}.", castedConfig.getPostTargetKey(), castedConfig.getChannelId(), castedConfig.getServerId());
postTargetManagement.createOrUpdate(castedConfig.getPostTargetKey(), castedConfig.getServerId(), castedConfig.getChannelId());
}
@Override

View File

@@ -72,15 +72,18 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep {
CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId());
Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId());
log.trace("Executing setup for post target {} in server {} for user {}.", postTargetStepParameter.getPostTargetKey(), user.getGuildId(), user.getUserId());
Consumer<MessageReceivedEvent> configAction = (MessageReceivedEvent event) -> {
try {
SetupStepResult result;
Message message = event.getMessage();
if(checkForExit(message)) {
log.info("Setup has been cancelled, because of 'exit' message.");
result = SetupStepResult.fromCancelled();
} else {
if(message.getMentionedChannels().size() == 0) {
log.trace("No mentioned channel was seen in channel, nothing provided.");
throw new NoChannelProvidedException();
}
TextChannel textChannel = message.getMentionedChannels().get(0);
@@ -91,6 +94,7 @@ public class PostTargetSetupStep extends AbstractConfigSetupStep {
.textChannel(textChannel)
.channelId(textChannel.getIdLong())
.build();
log.trace("Setup for post target {} in server {} for user {} completed. Storing delayed action.", postTargetStepParameter.getPostTargetKey(), user.getGuildId(), user.getUserId());
List<DelayedActionConfig> delayedSteps = Arrays.asList(build);
result = SetupStepResult
.builder()

View File

@@ -50,8 +50,10 @@ public class SetupSummaryStep extends AbstractConfigSetupStep {
CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId());
Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId());
log.info("Executing setup summary question step in server {} in channel {} from user {}.", user.getGuildId(), user.getChannelId(), user.getUserId());
Consumer<Void> confirmation = (Void none) -> {
try {
log.info("Setup summary was confirmed. Executing {} steps.", parameter.getDelayedActionList().size());
self.executeDelayedSteps(parameter);
SetupStepResult result = SetupStepResult
.builder()
@@ -59,11 +61,13 @@ public class SetupSummaryStep extends AbstractConfigSetupStep {
.build();
future.complete(result);
} catch (Exception e) {
log.error("Failed to execute {} delayed actions.", parameter.getDelayedActionList().size(), e);
future.completeExceptionally(e);
}
};
Consumer<Void> denial = (Void none) -> {
log.info("Setup summary was rejected. Cancelling execution of {} steps.", parameter.getDelayedActionList().size());
SetupStepResult result = SetupStepResult
.builder()
.result(SetupStepResultType.CANCELLED)

View File

@@ -1,10 +1,12 @@
package dev.sheldan.abstracto.core.interactive;
import dev.sheldan.abstracto.core.service.ConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class SystemConfigDelayedAction implements DelayedAction {
@@ -14,6 +16,7 @@ public class SystemConfigDelayedAction implements DelayedAction {
@Override
public void execute(DelayedActionConfig delayedActionConfig) {
SystemConfigDelayedActionConfig concrete = (SystemConfigDelayedActionConfig) delayedActionConfig;
log.trace("Executing delayed system config action for key {} in server {}.", concrete.getConfigKey(), concrete.getServerId());
configService.setConfigValue(concrete.getConfigKey(), concrete.getServerId(), concrete.getValue());
}

View File

@@ -62,19 +62,24 @@ public class SystemConfigSetupStep extends AbstractConfigSetupStep {
AChannel channel = channelManagementService.loadChannel(user.getChannelId());
CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(user.getGuildId(), user.getUserId());
log.trace("Executing setup for system config {} in server {} for user {}.", systemConfigStepParameter.getConfigKey(), user.getGuildId(), user.getUserId());
Runnable finalAction = super.getTimeoutRunnable(user.getGuildId(), user.getChannelId());
Consumer<MessageReceivedEvent> configAction = (MessageReceivedEvent event) -> {
try {
SetupStepResult result;
Message message = event.getMessage();
if(checkForExit(message)) {
log.info("Setup has been cancelled, because of 'exit' message.");
result = SetupStepResult.fromCancelled();
} else {
AConfig config;
if(checkForKeep(message)) {
config = self.loadDefaultConfig(systemConfigStepParameter);
log.info("It was decided to keep the original value for key {} in server {}.", systemConfigStepParameter.getConfigKey(), user.getGuildId());
} else {
config = self.checkValidity(user, systemConfigStepParameter, event);
log.trace("The given value for key {} in server {} was valid.", systemConfigStepParameter.getConfigKey(), user.getGuildId());
}
SystemConfigDelayedActionConfig build = SystemConfigDelayedActionConfig
.builder()
@@ -82,6 +87,7 @@ public class SystemConfigSetupStep extends AbstractConfigSetupStep {
.serverId(user.getGuildId())
.value(config)
.build();
log.trace("Setup for system config {} in server {} for user {} completed. Storing delayed action.", systemConfigStepParameter.getConfigKey(), user.getGuildId(), user.getUserId());
List<DelayedActionConfig> delayedSteps = Arrays.asList(build);
result = SetupStepResult
.builder()

View File

@@ -28,14 +28,14 @@ public class ChannelListener extends ListenerAdapter {
@Override
@Transactional
public void onTextChannelDelete(@Nonnull TextChannelDeleteEvent event) {
log.info("Handling channel delete event. Channel {}, Server {}", event.getChannel().getIdLong(), event.getGuild().getIdLong());
log.info("Handling channel delete event. Marking channel {} as deleted in server {}", event.getChannel().getIdLong(), event.getGuild().getIdLong());
channelManagementService.markAsDeleted(event.getChannel().getIdLong());
}
@Override
@Transactional
public void onTextChannelCreate(@Nonnull TextChannelCreateEvent event) {
log.info("Handling channel created event. Channel {}, Server {}", event.getChannel().getIdLong(), event.getGuild().getIdLong());
log.info("Handling channel created event. Creating channel {} in server {}", event.getChannel().getIdLong(), event.getGuild().getIdLong());
AServer serverObject = serverManagementService.loadOrCreate(event.getGuild().getIdLong());
TextChannel createdChannel = event.getChannel();
AChannelType type = AChannelType.getAChannelType(createdChannel.getType());

View File

@@ -4,11 +4,12 @@ import dev.sheldan.abstracto.core.command.service.CommandManager;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class CoreServiceConfigListener implements ServerConfigListener {
@Autowired
@@ -19,6 +20,8 @@ public class CoreServiceConfigListener implements ServerConfigListener {
@Override
public void updateServerConfig(AServer server) {
configManagementService.createIfNotExists(server.getId(), CommandManager.PREFIX, defaultConfigManagementService.getDefaultConfig(CommandManager.PREFIX).getStringValue());
log.info("Creating prefix config for server {}.", server.getId());
String defaultPrefix = defaultConfigManagementService.getDefaultConfig(CommandManager.PREFIX).getStringValue();
configManagementService.createIfNotExists(server.getId(), CommandManager.PREFIX, defaultPrefix);
}
}

View File

@@ -48,7 +48,10 @@ public class FeatureFlagListener implements ServerConfigListener {
AFeature feature = featureManagementService.getFeature(featureKey);
if(defaultFeatureKeys.contains(featureKey)) {
if(service.getFeatureFlag(feature, server.getId()) == null) {
log.info("Creating feature flag {} for server {}.", feature.getKey(), server.getId());
service.createFeatureFlag(feature, server.getId(), featureFlagKey.isEnabled());
} else {
log.trace("Feature flag {} for server {} already exists.", feature.getKey(), server.getId());
}
if(featureFlagKey.getMode() != null && !featureModeManagementService.featureModeSet(feature, server)) {
featureModeService.createMode(feature, server, featureFlagKey.getMode());

View File

@@ -32,6 +32,9 @@ public class JoinListenerBean extends ListenerAdapter {
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
private JoinListenerBean self;
@Override
@Transactional
public void onGuildMemberJoin(@Nonnull GuildMemberJoinEvent event) {
@@ -42,7 +45,7 @@ public class JoinListenerBean extends ListenerAdapter {
}
try {
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(event.getMember());
executeListener(event, joinListener, aUserInAServer);
self.executeIndividualJoinListener(event, joinListener, aUserInAServer);
} catch (Exception e) {
log.error("Listener {} failed with exception:", joinListener.getClass().getName(), e);
}
@@ -50,7 +53,8 @@ public class JoinListenerBean extends ListenerAdapter {
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeListener(@Nonnull GuildMemberJoinEvent event, JoinListener joinListener, AUserInAServer aUserInAServer) {
public void executeIndividualJoinListener(@Nonnull GuildMemberJoinEvent event, JoinListener joinListener, AUserInAServer aUserInAServer) {
log.trace("Executing join listener {} for member {} in guild {}.", joinListener.getClass().getName(), event.getMember().getId(), event.getGuild().getId());
joinListener.execute(event.getMember(), event.getGuild(), aUserInAServer);
}
}

View File

@@ -9,6 +9,7 @@ import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
@@ -27,6 +28,9 @@ public class LeaveListenerBean extends ListenerAdapter {
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private LeaveListenerBean self;
@Override
@Transactional
public void onGuildMemberRemove(@Nonnull GuildMemberRemoveEvent event) {
@@ -36,10 +40,16 @@ public class LeaveListenerBean extends ListenerAdapter {
return;
}
try {
leaveListener.execute(event.getMember(), event.getGuild());
self.executeIndividualLeaveListener(event, leaveListener);
} catch (AbstractoRunTimeException e) {
log.error("Listener {} failed with exception:", leaveListener.getClass().getName(), e);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualLeaveListener(@Nonnull GuildMemberRemoveEvent event, LeaveListener leaveListener) {
log.trace("Executing leave listener {} for member {} in guild {}.", leaveListener.getClass().getName(), event.getMember().getId(), event.getGuild().getId());
leaveListener.execute(event.getMember(), event.getGuild());
}
}

View File

@@ -18,6 +18,7 @@ import net.dv8tion.jda.api.events.message.guild.GuildMessageDeleteEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
@@ -88,10 +89,16 @@ public class MessageDeletedListenerBean extends ListenerAdapter {
return;
}
try {
messageDeletedListener.execute(cachedMessage, authorUser, authorMember);
self.executeIndividualMessageDeletedListener(cachedMessage, authorUser, authorMember, messageDeletedListener);
} catch (AbstractoRunTimeException e) {
log.error("Listener {} failed with exception:", messageDeletedListener.getClass().getName(), e);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualMessageDeletedListener(CachedMessage cachedMessage, AServerAChannelAUser authorUser, GuildChannelMember authorMember, MessageDeletedListener messageDeletedListener) {
log.trace("Executing message deleted listener {} for message {} in guild {}.", messageDeletedListener.getClass().getName(), cachedMessage.getMessageId(), cachedMessage.getMessageId());
messageDeletedListener.execute(cachedMessage, authorUser, authorMember);
}
}

View File

@@ -12,6 +12,8 @@ import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.List;
@@ -41,6 +43,9 @@ public class MessageReceivedListenerBean extends ListenerAdapter {
@Autowired
private ExceptionService exceptionService;
@Autowired
private MessageReceivedListenerBean self;
@Override
public void onGuildMessageReceived(@Nonnull GuildMessageReceivedEvent event) {
messageCache.putMessageInCache(event.getMessage());
@@ -50,7 +55,7 @@ public class MessageReceivedListenerBean extends ListenerAdapter {
if(!featureFlagService.isFeatureEnabled(feature, event.getGuild().getIdLong())) {
return;
}
messageReceivedListener.execute(event.getMessage());
self.executeIndividualGuildMessageReceivedListener(event, messageReceivedListener);
} catch (Exception e) {
log.error("Listener {} had exception when executing.", messageReceivedListener, e);
exceptionService.reportExceptionToGuildMessageReceivedContext(e, event);
@@ -58,6 +63,11 @@ public class MessageReceivedListenerBean extends ListenerAdapter {
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualGuildMessageReceivedListener(@Nonnull GuildMessageReceivedEvent event, MessageReceivedListener messageReceivedListener) {
messageReceivedListener.execute(event.getMessage());
}
@Override
public void onPrivateMessageReceived(@Nonnull PrivateMessageReceivedEvent event) {
if(event.getAuthor().getId().equals(botService.getInstance().getSelfUser().getId())) {
@@ -65,11 +75,17 @@ public class MessageReceivedListenerBean extends ListenerAdapter {
}
privateMessageReceivedListeners.forEach(messageReceivedListener -> {
try {
messageReceivedListener.execute(event.getMessage());
self.executeIndividualPrivateMessageReceivedListener(event, messageReceivedListener);
} catch (Exception e) {
log.error("Listener {} had exception when executing.", messageReceivedListener, e);
exceptionService.reportExceptionToPrivateMessageReceivedContext(e, event);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualPrivateMessageReceivedListener(@Nonnull PrivateMessageReceivedEvent event, PrivateMessageReceivedListener messageReceivedListener) {
log.trace("Executing private message listener {} for member {}.", messageReceivedListener.getClass().getName(), event.getAuthor().getId());
messageReceivedListener.execute(event.getMessage());
}
}

View File

@@ -12,6 +12,7 @@ import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
@@ -57,10 +58,15 @@ public class MessageUpdatedListener extends ListenerAdapter {
return;
}
try {
messageTextUpdatedListener.execute(cachedMessage, message);
self.executeIndividualMessageUpdatedListener(message, cachedMessage, messageTextUpdatedListener);
} catch (AbstractoRunTimeException e) {
log.error(String.format("Failed to execute listener. %s", messageTextUpdatedListener.getClass().getName()), e);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualMessageUpdatedListener(Message message, CachedMessage cachedMessage, MessageTextUpdatedListener messageTextUpdatedListener) {
messageTextUpdatedListener.execute(cachedMessage, message);
}
}

View File

@@ -14,6 +14,7 @@ import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionRemove
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
@@ -112,13 +113,18 @@ public class ReactionUpdatedListener extends ListenerAdapter {
return;
}
try {
reactedAddedListener.executeReactionAdded(cachedMessage, event, userInAServer);
self.executeIndividiualReactionAddedListener(event, cachedMessage, userInAServer, reactedAddedListener);
} catch (Exception e) {
log.warn(String.format("Failed to execute reaction added listener %s.", reactedAddedListener.getClass().getName()), e);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividiualReactionAddedListener(@Nonnull GuildMessageReactionAddEvent event, CachedMessage cachedMessage, AUserInAServer userInAServer, ReactedAddedListener reactedAddedListener) {
reactedAddedListener.executeReactionAdded(cachedMessage, event, userInAServer);
}
@Override
@Transactional
public void onGuildMessageReactionRemove(@Nonnull GuildMessageReactionRemoveEvent event) {
@@ -151,13 +157,18 @@ public class ReactionUpdatedListener extends ListenerAdapter {
return;
}
try {
reactionRemovedListener.executeReactionRemoved(cachedMessage, event, userInAServer);
self.executeIndividualReactionRemovedListener(event, cachedMessage, userInAServer, reactionRemovedListener);
} catch (AbstractoRunTimeException e) {
log.warn(String.format("Failed to execute reaction removed listener %s.", reactionRemovedListener.getClass().getName()), e);
}
});
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeIndividualReactionRemovedListener(@Nonnull GuildMessageReactionRemoveEvent event, CachedMessage cachedMessage, AUserInAServer userInAServer, ReactedRemovedListener reactionRemovedListener) {
reactionRemovedListener.executeReactionRemoved(cachedMessage, event, userInAServer);
}
@Transactional
public void callClearListeners(@Nonnull GuildMessageReactionRemoveAllEvent event, CachedMessage cachedMessage) {
clearedListenerList.forEach(reactionRemovedListener -> {

View File

@@ -30,6 +30,7 @@ public class RoleListener extends ListenerAdapter {
@Override
@Transactional
public void onRoleCreate(@Nonnull RoleCreateEvent event) {
log.info("Creating role {} in server {}.", event.getRole().getId(), event.getGuild().getId());
AServer server = serverManagementService.loadOrCreate(event.getGuild().getIdLong());
service.createRole(event.getRole().getIdLong(), server);
}
@@ -37,6 +38,7 @@ public class RoleListener extends ListenerAdapter {
@Override
@Transactional
public void onRoleDelete(@Nonnull RoleDeleteEvent event) {
log.info("Marking role {} as deleted in server {}.", event.getRole().getId(), event.getGuild().getId());
AServer server = serverManagementService.loadOrCreate(event.getGuild().getIdLong());
roleService.markDeleted(event.getRole(), server);
}

View File

@@ -2,16 +2,19 @@ package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.guild.GuildJoinEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import java.util.List;
@Component
@Slf4j
public class ServerJoinListener extends ListenerAdapter {
@Autowired
@@ -20,10 +23,20 @@ public class ServerJoinListener extends ListenerAdapter {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private ServerJoinListener self;
@Override
@Transactional
public void onGuildJoin(@Nonnull GuildJoinEvent event) {
log.info("Joining guild {}, executing server config listener.", event.getGuild().getId());
AServer server = serverManagementService.loadOrCreate(event.getGuild().getIdLong());
configListeners.forEach(serverConfigListener -> serverConfigListener.updateServerConfig(server));
configListeners.forEach(serverConfigListener -> self.executingIndividualServerConfigListener(server, serverConfigListener));
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executingIndividualServerConfigListener(AServer server, ServerConfigListener serverConfigListener) {
log.trace("Executing server config listener for server {}.", server.getId());
serverConfigListener.updateServerConfig(server);
}
}

View File

@@ -49,6 +49,7 @@ public class BotServiceBean implements BotService {
@Override
public GuildChannelMember getServerChannelUser(Long serverId, Long channelId, Long userId) {
log.trace("Trying to retrieve member {}, channel {} in server {} from cache.", userId, channelId, serverId);
Optional<Guild> guildOptional = getGuildById(serverId);
if(guildOptional.isPresent()) {
Guild guild = guildOptional.get();
@@ -68,6 +69,7 @@ public class BotServiceBean implements BotService {
@Override
public Member getMemberInServer(Long serverId, Long memberId) {
log.trace("Retrieving member {} in server {} from cache.", memberId, serverId);
Guild guildById = instance.getGuildById(serverId);
if(guildById != null) {
return guildById.getMemberById(memberId);

View File

@@ -29,6 +29,7 @@ public class CacheServiceBean {
}
public void clearCaches() {
log.info("Clearing all caches.");
sessionFactory.getCache().evictAllRegions();
templateService.clearCache();
}

View File

@@ -70,11 +70,14 @@ public class ChannelServiceBean implements ChannelService {
@Override
public CompletableFuture<Message> sendMessageToChannel(Message message, MessageChannel channel) {
log.trace("Sending message {} from channel {} and server {} to channel {}.",
message.getId(), message.getChannel().getId(), message.getGuild().getId(), channel.getId());
return channel.sendMessage(message).submit();
}
@Override
public CompletableFuture<Message> sendTextToChannel(String text, MessageChannel channel) {
log.trace("Sending text to channel {}.", channel.getId());
return channel.sendMessage(text).submit();
}
@@ -97,6 +100,7 @@ public class ChannelServiceBean implements ChannelService {
@Override
public CompletableFuture<Message> sendEmbedToChannel(MessageEmbed embed, MessageChannel channel) {
log.trace("Sending embed to channel {}.", channel.getId());
return channel.sendMessage(embed).submit();
}
@@ -119,14 +123,17 @@ public class ChannelServiceBean implements ChannelService {
String messageText = messageToSend.getMessage();
List<CompletableFuture<Message>> futures = new ArrayList<>();
if(StringUtils.isBlank(messageText)) {
log.trace("Only sending {} embeds to channel {}.", messageToSend.getEmbeds().size(), textChannel.getId());
messageToSend.getEmbeds().forEach(embed ->
futures.add(sendEmbedToChannel(embed, textChannel))
);
} else {
log.trace("Sending mesagte text to channel {}.", textChannel.getId());
MessageAction messageAction = textChannel.sendMessage(messageText);
if(messageToSend.getEmbeds() != null && !messageToSend.getEmbeds().isEmpty()) {
CompletableFuture<Message> messageFuture = messageAction.embed(messageToSend.getEmbeds().get(0)).submit();
futures.add(messageFuture);
log.trace("Also sending {} embeds to channel {}.", messageToSend.getEmbeds().size(), textChannel.getId());
CompletableFuture<Message> firstMessageFuture = messageAction.embed(messageToSend.getEmbeds().get(0)).submit();
futures.add(firstMessageFuture);
messageToSend.getEmbeds().stream().skip(1).forEach(embed ->
futures.add(sendEmbedToChannel(embed, textChannel))
);
@@ -162,11 +169,14 @@ public class ChannelServiceBean implements ChannelService {
public CompletableFuture<Message> editMessageInAChannelFuture(MessageToSend messageToSend, MessageChannel channel, Long messageId) {
MessageAction messageAction;
if(!StringUtils.isBlank(messageToSend.getMessage())) {
log.trace("Editing message {} with new text content.", messageId);
messageAction = channel.editMessageById(messageId, messageToSend.getMessage());
if(messageToSend.getEmbeds() != null && !messageToSend.getEmbeds().isEmpty()) {
log.trace("Also editing the embed for message {}.", messageId);
messageAction = messageAction.embed(messageToSend.getEmbeds().get(0));
}
} else {
log.trace("Editing message {} with new embeds.", messageId);
if(messageToSend.getEmbeds() != null && !messageToSend.getEmbeds().isEmpty()) {
messageAction = channel.editMessageById(messageId, messageToSend.getEmbeds().get(0));
} else {
@@ -207,6 +217,7 @@ public class ChannelServiceBean implements ChannelService {
return channel.retrieveMessageById(messageId).submit().thenCompose(message -> {
EmbedBuilder embedBuilder = new EmbedBuilder(message.getEmbeds().get(embedIndex));
embedBuilder.getFields().remove(index.intValue());
log.trace("Removing field with index {} from message {}.", index, messageId);
return channel.editMessageById(messageId, embedBuilder.build()).submit();
});
}
@@ -220,6 +231,7 @@ public class ChannelServiceBean implements ChannelService {
public CompletableFuture<Void> deleteTextChannel(Long serverId, Long channelId) {
TextChannel textChannelById = botService.getInstance().getTextChannelById(channelId);
if(textChannelById != null) {
log.info("Deleting channel {} on server {}.", channelId, serverId);
return textChannelById.delete().submit();
}
throw new ChannelNotFoundException(channelId);
@@ -245,6 +257,7 @@ public class ChannelServiceBean implements ChannelService {
Guild guild = guildById.get();
Category categoryById = guild.getCategoryById(categoryId);
if(categoryById != null) {
log.info("Creating channel on server {} in category {}.", server.getId(), categoryById);
return categoryById.createTextChannel(name).submit();
}
throw new CategoryNotFoundException(categoryId, server.getId());

View File

@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.exception.InvalidConditionParametersException;
import dev.sheldan.abstracto.core.models.ConditionContextInstance;
import dev.sheldan.abstracto.core.models.ConditionContextVariable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -11,6 +12,7 @@ import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class ConditionServiceBean implements ConditionService {
@Autowired
@@ -22,9 +24,12 @@ public class ConditionServiceBean implements ConditionService {
.stream()
.filter(systemCondition -> systemCondition.getConditionName().equalsIgnoreCase(context.getConditionName()))
.findAny();
log.trace("Checking condition {}.", context.getConditionName());
return matchingCondition.map(systemCondition -> {
verifyConditionContext(context, systemCondition);
return systemCondition.checkCondition(context);
boolean result = systemCondition.checkCondition(context);
log.trace("Condition resulted in {}.", result);
return result;
}).orElse(true);
}

View File

@@ -2,10 +2,12 @@ package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.repository.CounterRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class CounterServiceBean implements CounterService {
@Autowired
@@ -13,6 +15,7 @@ public class CounterServiceBean implements CounterService {
@Override
public Long getNextCounterValue(AServer server, String key) {
log.trace("Retrieving new counter value for key {} in server {}.", key, server.getId());
return counterRepository.getNewCounterForKey(server.getId(), key);
}
}

View File

@@ -2,12 +2,14 @@ package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.interactive.DelayedAction;
import dev.sheldan.abstracto.core.interactive.DelayedActionConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class DelayedActionServiceBean implements DelayedActionService {
@Autowired
@@ -15,11 +17,12 @@ public class DelayedActionServiceBean implements DelayedActionService {
@Override
public void executeDelayedActions(List<DelayedActionConfig> delayedActionConfigList) {
delayedActionConfigList.forEach(delayedActionConfig ->
delayedActionConfigList.forEach(delayedActionConfig -> {
log.trace("Executing delayed action {}.", delayedActionConfig.getClass().getSimpleName());
delayedActions.stream()
.filter(delayedAction -> delayedAction.handles(delayedActionConfig))
.findFirst()
.ifPresent(delayedAction -> delayedAction.execute(delayedActionConfig))
);
.ifPresent(delayedAction -> delayedAction.execute(delayedActionConfig));
});
}
}

View File

@@ -9,6 +9,7 @@ import dev.sheldan.abstracto.core.exception.FeatureModeNotFoundException;
import dev.sheldan.abstracto.core.exception.FeatureNotFoundException;
import dev.sheldan.abstracto.core.models.FeatureValidationResult;
import dev.sheldan.abstracto.core.models.database.AServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -18,6 +19,7 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
@Component
@Slf4j
public class FeatureConfigServiceBean implements FeatureConfigService {
@Autowired
@@ -99,19 +101,24 @@ public class FeatureConfigServiceBean implements FeatureConfigService {
@Override
public FeatureValidationResult validateFeatureSetup(FeatureConfig featureConfig, AServer server) {
log.info("Verifying feature setup for feature {} in server {}.", featureConfig.getFeature().getKey(), server.getId());
FeatureValidationResult featureValidationResult = FeatureValidationResult.validationSuccessful(featureConfig);
featureConfig.getRequiredPostTargets().forEach(s ->
featureValidatorService.checkPostTarget(s, server, featureValidationResult)
);
featureConfig.getRequiredSystemConfigKeys().forEach(s ->
featureValidatorService.checkSystemConfig(s, server, featureValidationResult)
);
featureConfig.getRequiredEmotes().forEach(s ->
featureValidatorService.checkEmote(s, server, featureValidationResult)
);
featureConfig.getAdditionalFeatureValidators().forEach(featureValidator ->
featureValidator.featureIsSetup(featureConfig, server, featureValidationResult)
);
featureConfig.getRequiredPostTargets().forEach(s -> {
log.trace("Checking post target {}.", s.getKey());
featureValidatorService.checkPostTarget(s, server, featureValidationResult);
});
featureConfig.getRequiredSystemConfigKeys().forEach(s -> {
log.trace("Checking system config key {}.", s);
featureValidatorService.checkSystemConfig(s, server, featureValidationResult);
});
featureConfig.getRequiredEmotes().forEach(s -> {
log.trace("Checking required emote {}.", s);
featureValidatorService.checkEmote(s, server, featureValidationResult);
} );
featureConfig.getAdditionalFeatureValidators().forEach(featureValidator -> {
log.trace("Executing additional feature validator {}.", featureValidator.getClass().getName());
featureValidator.featureIsSetup(featureConfig, server, featureValidationResult);
});
return featureValidationResult;
}

View File

@@ -10,6 +10,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.EmoteManagementService;
import dev.sheldan.abstracto.core.service.management.PostTargetManagement;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
@@ -18,6 +19,7 @@ import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class FeatureValidationServiceBean implements FeatureValidatorService {
@Autowired
@@ -38,6 +40,7 @@ public class FeatureValidationServiceBean implements FeatureValidatorService {
@Override
public void checkPostTarget(PostTargetEnum name, AServer server, FeatureValidationResult featureValidationResult) {
if(!postTargetManagement.postTargetExists(name.getKey(), server)) {
log.info("Rejecting feature validation because of post target {}.", name.getKey());
PostTargetValidationErrorModel validationError = PostTargetValidationErrorModel.builder().postTargetName(name.getKey()).build();
featureValidationResult.setValidationResult(false);
featureValidationResult.getValidationErrorModels().add(validationError);
@@ -47,6 +50,7 @@ public class FeatureValidationServiceBean implements FeatureValidatorService {
@Override
public boolean checkSystemConfig(String name, AServer server, FeatureValidationResult featureValidationResult) {
if(!configService.configExists(server, name)) {
log.info("Rejecting feature validation because of system config key {}.", name);
SystemConfigValidationErrorModel validationError = SystemConfigValidationErrorModel.builder().configKey(name).build();
featureValidationResult.setValidationResult(false);
featureValidationResult.getValidationErrorModels().add(validationError);
@@ -79,6 +83,7 @@ public class FeatureValidationServiceBean implements FeatureValidatorService {
}
private void rejectEmote(String emoteKey, FeatureValidationResult featureValidationResult) {
log.info("Rejecting feature validation because of emote {}", emoteKey);
EmoteMissingValidationErrorModel validationError = EmoteMissingValidationErrorModel.builder().emoteKey(emoteKey).build();
featureValidationResult.setValidationResult(false);
featureValidationResult.getValidationErrorModels().add(validationError);

View File

@@ -39,11 +39,6 @@ public class MessageCacheBean implements MessageCache {
@Autowired
private UserInServerManagementService userInServerManagementService;
@Autowired
@Lazy
// needs to be lazy, because of circular dependency
private MessageCache self;
@Autowired
@Lazy
// needs to be lazy, because of circular dependency
@@ -52,31 +47,30 @@ public class MessageCacheBean implements MessageCache {
@Override
@CachePut(key = "#message.id")
public CompletableFuture<CachedMessage> putMessageInCache(Message message) {
log.info("Adding message {} to cache", message.getId());
return self.buildCachedMessageFromMessage(message);
log.trace("Adding message {} to cache", message.getId());
return concreteSelf.buildCachedMessageFromMessage(message);
}
@Override
@CachePut(key = "#message.messageId.toString()")
public CompletableFuture<CachedMessage> putMessageInCache(CachedMessage message) {
log.info("Adding cached message to cache");
log.trace("Adding cached message to cache");
return CompletableFuture.completedFuture(message);
}
@Override
@Cacheable(key = "#message.id")
public CompletableFuture<CachedMessage> getMessageFromCache(Message message) {
log.info("Retrieving message {}", message.getId());
log.trace("Retrieving message {}", message.getId());
return getMessageFromCache(message.getGuild().getIdLong(), message.getChannel().getIdLong(), message.getIdLong());
}
@Override
@Cacheable(key = "#messageId.toString()")
public CompletableFuture<CachedMessage> getMessageFromCache(Long guildId, Long textChannelId, Long messageId) {
log.info("Retrieving message with parameters");
return self.loadMessage(guildId, textChannelId, messageId);
log.trace("Retrieving message with parameters");
return concreteSelf.loadMessage(guildId, textChannelId, messageId);
}
@Override
@@ -123,7 +117,7 @@ public class MessageCacheBean implements MessageCache {
);
List<CompletableFuture<CachedReaction>> futures = new ArrayList<>();
message.getReactions().forEach(messageReaction -> futures.add(self.getCachedReactionFromReaction(messageReaction)));
message.getReactions().forEach(messageReaction -> futures.add(concreteSelf.getCachedReactionFromReaction(messageReaction)));
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid ->
future.complete(CachedMessage.builder()

View File

@@ -71,12 +71,14 @@ public class MessageServiceBean implements MessageService {
if(Boolean.TRUE.equals(emote.getCustom())) {
Emote emoteById = botService.getInstance().getEmoteById(emote.getEmoteId());
if(emoteById != null) {
log.trace("Adding custom emote {} as reaction to message {}.", emoteById.getId(), message.getId());
return message.addReaction(emoteById).submit();
} else {
log.error("Emote with key {} and id {} for guild {} was not found.", emote.getName() , emote.getEmoteId(), guild.getId());
throw new ConfiguredEmoteNotUsableException(emote);
}
} else {
log.trace("Adding default emote {} as reaction to message {}.", emote.getEmoteKey(), message.getId());
return message.addReaction(emote.getEmoteKey()).submit();
}
}
@@ -97,8 +99,10 @@ public class MessageServiceBean implements MessageService {
if(emoteById == null) {
throw new EmoteNotInServerException(emote.getEmoteId());
}
log.trace("Removing single custom reaction for emote {} on message {}.", emoteById.getId(), message.getId());
return message.removeReaction(emoteById).submit();
} else {
log.trace("Removing single default emote {} reaction from message {}.", emote.getEmoteKey(), message.getId());
return message.removeReaction(emote.getEmoteKey()).submit();
}
}
@@ -110,8 +114,10 @@ public class MessageServiceBean implements MessageService {
if(emoteById == null) {
throw new EmoteNotInServerException(emote.getEmoteId());
}
log.trace("Clearing reactions for custom emote {} on message {}.", emoteById.getId(), message.getId());
return message.clearReactions(emoteById).submit();
} else {
log.trace("Clearing reactions for default emote {} on message {}.", emote.getEmoteKey(), message.getId());
return message.clearReactions(emote.getEmoteKey()).submit();
}
}
@@ -158,8 +164,10 @@ public class MessageServiceBean implements MessageService {
if(emoteById == null) {
throw new EmoteNotInServerException(emote.getEmoteId());
}
log.trace("Removing reaction for custom emote {} from user {} on message {}.", emoteById.getId(), member.getId(), member.getId());
return message.removeReaction(emoteById, member.getUser()).submit();
} else {
log.trace("Removing reaction for default emote {} from user {} on message {}.", emote.getEmoteKey(), member.getId(), member.getId());
return message.removeReaction(emote.getEmoteKey(), member.getUser()).submit();
}
}
@@ -249,12 +257,14 @@ public class MessageServiceBean implements MessageService {
@Override
public CompletableFuture<Message> sendEmbedToUserWithMessage(User user, String template, Object model) {
log.trace("Sending direct message with template {} to user {}.", template, user.getIdLong());
return user.openPrivateChannel().submit().thenCompose(privateChannel ->
channelService.sendEmbedTemplateInChannel(template, model, privateChannel).get(0));
}
@Override
public CompletableFuture<Message> sendMessageToUser(User user, String text) {
log.trace("Sending direct string message to user {}.", user.getIdLong());
return user.openPrivateChannel().flatMap(privateChannel -> privateChannel.sendMessage(text)).submit();
}
}

View File

@@ -50,12 +50,14 @@ public class PostTargetServiceBean implements PostTargetService {
@Override
public CompletableFuture<Message> sendTextInPostTarget(String text, PostTarget target) {
log.trace("Sending text to post target {}.", target.getName());
return channelService.sendTextToAChannel(text, target.getChannelReference());
}
@Override
public CompletableFuture<Message> sendEmbedInPostTarget(MessageEmbed embed, PostTarget target) {
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
log.trace("Sending message embed to post target {}.", target.getName());
return textChannelForPostTarget.sendMessage(embed).submit();
}
@@ -105,6 +107,7 @@ public class PostTargetServiceBean implements PostTargetService {
@Override
public CompletableFuture<Message> sendMessageInPostTarget(Message message, PostTarget target) {
log.trace("Send message {} towards post target {}.", message.getId(), target.getName());
return channelService.sendMessageToAChannel(message, target.getChannelReference());
}
@@ -117,6 +120,7 @@ public class PostTargetServiceBean implements PostTargetService {
@Override
public List<CompletableFuture<Message>> sendEmbedInPostTarget(MessageToSend message, PostTarget target) {
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
log.trace("Send messageToSend towards post target {}.", target.getName());
return channelService.sendMessageToSendToChannel(message, textChannelForPostTarget);
}
@@ -125,8 +129,10 @@ public class PostTargetServiceBean implements PostTargetService {
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
String messageText = message.getMessage();
if(StringUtils.isBlank(messageText)) {
log.trace("Editing embeds of message {} in post target {}.", messageId, target.getName());
return Arrays.asList(textChannelForPostTarget.editMessageById(messageId, message.getEmbeds().get(0)).submit());
} else {
log.trace("Editing message text and potentially text for message {} in post target {}.", messageId, target.getName());
return Arrays.asList(textChannelForPostTarget.editMessageById(messageId, messageText).embed(message.getEmbeds().get(0)).submit());
}
}
@@ -141,33 +147,45 @@ public class PostTargetServiceBean implements PostTargetService {
textChannelForPostTarget
.retrieveMessageById(messageId)
.queue(
existingMessage -> existingMessage
existingMessage -> {
log.trace("Editing existing message {} when upserting message embeds in channel {} in server {}.",
messageId, textChannelForPostTarget.getIdLong(), textChannelForPostTarget.getGuild().getId());
existingMessage
.editMessage(messageToSend.getEmbeds().get(0))
.queue(messageEditFuture::complete, messageEditFuture::completeExceptionally),
throwable ->
sendEmbedInPostTarget(messageToSend, target).get(0)
.thenAccept(messageEditFuture::complete).exceptionally(innerThrowable -> {
log.error("Failed to send message to create a message.", innerThrowable);
messageEditFuture.completeExceptionally(innerThrowable);
return null;
})
);
} else {
textChannelForPostTarget
.retrieveMessageById(messageId)
.queue(
existingMessage -> existingMessage
.editMessage(messageToSend.getMessage())
.embed(messageToSend.getEmbeds().get(0))
.queue(messageEditFuture::complete, messageEditFuture::completeExceptionally),
throwable ->
.queue(messageEditFuture::complete, messageEditFuture::completeExceptionally);
},
throwable -> {
log.trace("Creating new message when upserting message embeds for message {} in channel {} in server {}.",
messageId, textChannelForPostTarget.getIdLong(), textChannelForPostTarget.getGuild().getId());
sendEmbedInPostTarget(messageToSend, target).get(0)
.thenAccept(messageEditFuture::complete).exceptionally(innerThrowable -> {
log.error("Failed to send message to create a message.", innerThrowable);
messageEditFuture.completeExceptionally(innerThrowable);
return null;
})
);
});
});
} else {
textChannelForPostTarget
.retrieveMessageById(messageId)
.queue(
existingMessage -> {
log.trace("Editing existing message {} when upserting message in channel {} in server {}.",
messageId, textChannelForPostTarget.getIdLong(), textChannelForPostTarget.getGuild().getId());
existingMessage
.editMessage(messageToSend.getMessage())
.embed(messageToSend.getEmbeds().get(0))
.queue(messageEditFuture::complete, messageEditFuture::completeExceptionally);
},
throwable -> {
log.trace("Creating new message when trying to upsert a message {} in channel {} in server {}.",
messageId, textChannelForPostTarget.getIdLong(), textChannelForPostTarget.getGuild().getId());
sendEmbedInPostTarget(messageToSend, target).get(0)
.thenAccept(messageEditFuture::complete).exceptionally(innerThrowable -> {
log.error("Failed to send message to create a message.", innerThrowable);
messageEditFuture.completeExceptionally(innerThrowable);
return null;
});
});
}
return futures;

View File

@@ -81,6 +81,7 @@ public class RoleServiceBean implements RoleService {
}
Role roleById = guild.getRoleById(role.getId());
if(roleById != null) {
log.info("Adding role {} to user {} in server {}.", role.getId(), userId, guild.getId());
return guild.addRoleToMember(userId, roleById).submit();
} else {
throw new RoleNotFoundInGuildException(role.getId(), guild.getIdLong());
@@ -99,6 +100,7 @@ public class RoleServiceBean implements RoleService {
}
Role roleById = guild.getRoleById(role.getId());
if(roleById != null) {
log.info("Removing role {} from user {} in server {}.", role.getId(), userId, guild.getId());
return guild.removeRoleFromMember(userId, roleById).submit();
} else {
throw new RoleNotFoundInGuildException(role.getId(), guild.getIdLong());
@@ -150,6 +152,7 @@ public class RoleServiceBean implements RoleService {
}
Optional<Guild> guildById = botService.getGuildById(role.getServer().getId());
if(guildById.isPresent()) {
log.trace("Loading role {} from server {}.", role.getId(), role.getServer().getId());
return guildById.get().getRoleById(role.getId());
} else {
throw new GuildNotFoundException(role.getServer().getId());

View File

@@ -54,46 +54,51 @@ public class SetupServiceBean implements SetupService {
@Override
public CompletableFuture<Void> performSetup(FeatureConfig featureConfig, AServerChannelUserId user, Long initialMessageId) {
List<String> requiredSystemConfigKeys = featureConfig.getRequiredSystemConfigKeys();
List<SetupExecution> steps = new ArrayList<>();
requiredSystemConfigKeys.forEach(s -> {
SetupExecution execution = SetupExecution
.builder()
.step(systemConfigSetupStep)
.parameter(SystemConfigStepParameter.builder().configKey(s).build())
.build();
steps.add(execution);
});
featureConfig.getRequiredPostTargets().forEach(postTargetEnum -> {
SetupExecution execution = SetupExecution
.builder()
.step(postTargetSetupStep)
.parameter(PostTargetStepParameter.builder().postTargetKey(postTargetEnum.getKey()).build())
.build();
steps.add(execution);
});
featureConfig.getCustomSetupSteps().forEach(setupStep -> {
SetupExecution execution = SetupExecution
.builder()
.step(setupStep)
.parameter(EmptySetupParameter.builder().build())
.build();
steps.add(execution);
});
for (int i = 0; i < steps.size(); i++) {
SetupExecution setupExecution = steps.get(i);
setupExecution.getParameter().setPreviousMessageId(initialMessageId);
if(i < steps.size() - 1) {
setupExecution.setNextStep(steps.get(i + 1));
}
}
SetupInitialMessageModel setupInitialMessageModel = SetupInitialMessageModel
.builder()
.featureConfig(featureConfig)
.build();
log.info("Performing setup of feature {} for user {} in channel {} in server {}.",
featureConfig.getFeature().getKey(), user.getUserId(), user.getChannelId(), user.getGuildId());
Optional<TextChannel> textChannelInGuild = channelService.getTextChannelInGuild(user.getGuildId(), user.getChannelId());
if(textChannelInGuild.isPresent()) {
List<String> requiredSystemConfigKeys = featureConfig.getRequiredSystemConfigKeys();
List<SetupExecution> steps = new ArrayList<>();
requiredSystemConfigKeys.forEach(s -> {
log.trace("Feature requires system config key {}.", s);
SetupExecution execution = SetupExecution
.builder()
.step(systemConfigSetupStep)
.parameter(SystemConfigStepParameter.builder().configKey(s).build())
.build();
steps.add(execution);
});
featureConfig.getRequiredPostTargets().forEach(postTargetEnum -> {
log.trace("Feature requires post target {}.", postTargetEnum.getKey());
SetupExecution execution = SetupExecution
.builder()
.step(postTargetSetupStep)
.parameter(PostTargetStepParameter.builder().postTargetKey(postTargetEnum.getKey()).build())
.build();
steps.add(execution);
});
featureConfig.getCustomSetupSteps().forEach(setupStep -> {
log.trace("Feature requires custom setup step {}.", setupStep.getClass().getName());
SetupExecution execution = SetupExecution
.builder()
.step(setupStep)
.parameter(EmptySetupParameter.builder().build())
.build();
steps.add(execution);
});
for (int i = 0; i < steps.size(); i++) {
SetupExecution setupExecution = steps.get(i);
setupExecution.getParameter().setPreviousMessageId(initialMessageId);
if(i < steps.size() - 1) {
setupExecution.setNextStep(steps.get(i + 1));
}
}
SetupInitialMessageModel setupInitialMessageModel = SetupInitialMessageModel
.builder()
.featureConfig(featureConfig)
.build();
TextChannel textChannel = textChannelInGuild.get();
String text = templateService.renderTemplate("setup_initial_message", setupInitialMessageModel);
channelService.sendTextToChannel(text, textChannel);
@@ -109,15 +114,20 @@ public class SetupServiceBean implements SetupService {
}
private CompletableFuture<Void> executeStep(AServerChannelUserId aUserInAServer, SetupExecution execution, List<DelayedActionConfig> delayedActionConfigs, FeatureConfig featureConfig) {
log.trace("Executing step {} in server {} in channel {} for user {}.", execution.getStep().getClass(), aUserInAServer.getGuildId(), aUserInAServer.getChannelId(), aUserInAServer.getUserId());
return execution.getStep().execute(aUserInAServer, execution.getParameter()).thenAccept(aVoid -> {
if(aVoid.getResult().equals(SetupStepResultType.SUCCESS)) {
log.info("Step {} in server {} has been executed successfully. Proceeding.", execution.getStep().getClass(), aUserInAServer.getGuildId());
delayedActionConfigs.addAll(aVoid.getDelayedActionConfigList());
if(execution.getNextStep() != null) {
log.trace("Executing next step {}.", execution.getNextStep().getStep().getClass());
executeStep(aUserInAServer, execution.getNextStep(), delayedActionConfigs, featureConfig);
} else {
log.trace("Step was the last step. Executing post setup steps.");
self.executePostSetupSteps(delayedActionConfigs, aUserInAServer, execution.getParameter().getPreviousMessageId(), featureConfig);
}
} else {
log.info("Result of step {} has been {}. Notifying user.", execution.getStep().getClass(), SetupStepResultType.CANCELLED);
self.notifyAboutCancellation(aUserInAServer, featureConfig);
}
@@ -147,6 +157,8 @@ public class SetupServiceBean implements SetupService {
@Transactional
public void notifyAboutCompletion(AServerChannelUserId aServerChannelUserId, FeatureConfig featureConfig) {
log.trace("Notifying user {} in channel {} in server {} about completion of setup for feature {}.",
aServerChannelUserId.getUserId(), aServerChannelUserId.getChannelId(), aServerChannelUserId.getGuildId(), featureConfig.getFeature().getKey());
notifyUserWithTemplate(aServerChannelUserId, featureConfig, "setup_completion_notification");
}
@@ -162,6 +174,8 @@ public class SetupServiceBean implements SetupService {
@Transactional
public void notifyAboutCancellation(AServerChannelUserId aServerChannelUserId, FeatureConfig featureConfig) {
log.trace("Notifying user {} in channel {} in server {} about cancellation of setup for feature {}.",
aServerChannelUserId.getUserId(), aServerChannelUserId.getChannelId(), aServerChannelUserId.getGuildId(), featureConfig.getFeature().getKey());
notifyUserWithTemplate(aServerChannelUserId, featureConfig, "setup_cancellation_notification");
}
}

View File

@@ -89,9 +89,8 @@ public class StartupServiceBean implements Startup {
Set<Long> availableRoles = SnowflakeUtils.getSnowflakeIds(existingRoles);
Set<Long> newRoles = SetUtils.difference(availableRoles, knownRolesId);
newRoles.forEach(aLong -> {
ARole newRole = roleManagementService.createRole(aLong, existingAServer);
roleManagementService.createRole(aLong, existingAServer);
log.trace("Adding new role: {}", aLong);
existingAServer.getRoles().add(newRole);
});
}

View File

@@ -29,6 +29,7 @@ public class UndoActionServiceBean implements UndoActionService {
@Override
public CompletableFuture<Void> performActionsFuture(List<UndoActionInstance> actionsToPerform) {
List<CompletableFuture<Void>> futures = new ArrayList<>();
log.info("Performing {} undo actions.", actionsToPerform.size());
actionsToPerform.forEach(undoActionInstance -> {
UndoAction action = undoActionInstance.getAction();
List<Long> ids = undoActionInstance.getIds();
@@ -37,12 +38,14 @@ public class UndoActionServiceBean implements UndoActionService {
log.error("Not the correct amount of ids provided for the channel deletion undo action.");
return;
}
log.info("Deleting channel {} in guild {} because of an UNDO action.", ids.get(1), ids.get(0));
futures.add(deleteChannel(ids.get(0), ids.get(1)));
} else if(action.equals(UndoAction.DELETE_MESSAGE)) {
if(ids.size() != 2) {
log.error("Not the correct amount of ids provided for the message deletion undo action.");
return;
}
log.info("Deleting message {} in channel {} because of an UNDO action.", ids.get(1), ids.get(0));
futures.add(botService.deleteMessage(ids.get(0), ids.get(1)));
}
});

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.repository.ChannelGroupRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -16,6 +17,7 @@ import java.util.function.Predicate;
import java.util.stream.Collectors;
@Component
@Slf4j
public class ChannelGroupManagementServiceBean implements ChannelGroupManagementService {
@Autowired
@@ -35,6 +37,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
.groupName(name)
.server(server)
.build();
log.info("Creating new channel group in server {}.", server.getId());
channelGroupRepository.save(channelGroup);
return channelGroup;
}
@@ -51,6 +54,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
if(existing == null) {
throw new ChannelGroupNotFoundException(name, getAllAvailableAsString(server));
}
log.info("Deleting channel group {} in server {}.", existing.getId(), server.getId());
channelGroupRepository.delete(existing);
}
@@ -62,6 +66,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
}
channelGroup.getChannels().add(channel);
channel.getGroups().add(channelGroup);
log.info("Adding channel {} to channel group {} in server {}.", channel.getId(), channelGroup.getId(), channel.getServer().getId());
return channelGroup;
}
@@ -73,6 +78,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
}
channelGroup.getChannels().removeIf(channelInGroupPredicate);
channel.getGroups().removeIf(channelGroup1 -> channelGroup1.getId().equals(channelGroup.getId()));
log.info("Removing channel {} from channel group {} in server {}.", channel.getId(), channelGroup.getId(), channel.getServer().getId());
}
@Override

View File

@@ -56,6 +56,7 @@ public class ChannelManagementServiceBean implements ChannelManagementService {
public AChannel markAsDeleted(Long id) {
AChannel channel = loadChannel(id);
channel.setDeleted(true);
log.info("Marking channel {} as deleted.", id);
return channel;
}

View File

@@ -21,7 +21,7 @@ public class ConfigManagementServiceBean implements ConfigManagementService {
public AConfig setOrCreateStringValue(Long serverId, String name, String value) {
AConfig config = loadConfig(serverId, name);
if(config == null) {
createConfig(serverId, name, value);
config = createConfig(serverId, name, value);
} else {
config.setStringValue(value);
}
@@ -32,7 +32,7 @@ public class ConfigManagementServiceBean implements ConfigManagementService {
public AConfig setOrCreateDoubleValue(Long serverId, String name, Double value) {
AConfig config = loadConfig(serverId, name);
if(config == null) {
createConfig(serverId, name, value);
config = createConfig(serverId, name, value);
} else {
config.setDoubleValue(value);
}
@@ -48,6 +48,7 @@ public class ConfigManagementServiceBean implements ConfigManagementService {
.server(server)
.name(name)
.build();
log.trace("Creating config entry for type string in server {} and key {}", serverId, name);
configRepository.save(config);
return config;
}
@@ -61,6 +62,7 @@ public class ConfigManagementServiceBean implements ConfigManagementService {
.server(server)
.name(name)
.build();
log.trace("Creating config entry for type double in server {} and key {}", serverId, name);
configRepository.save(config);
return config;
}
@@ -75,6 +77,7 @@ public class ConfigManagementServiceBean implements ConfigManagementService {
.name(name)
.build();
configRepository.save(config);
log.trace("Creating config entry for type long in server {} and key {}", serverId, name);
return config;
}
@@ -124,6 +127,7 @@ public class ConfigManagementServiceBean implements ConfigManagementService {
public AConfig setDoubleValue(Long serverId, String name, Double value) {
AConfig config = loadConfig(serverId, name);
config.setDoubleValue(value);
log.trace("Setting double value of key {} in server {}.", name, serverId);
return config;
}
@@ -131,6 +135,7 @@ public class ConfigManagementServiceBean implements ConfigManagementService {
public AConfig setLongValue(Long serverId, String name, Long value) {
AConfig config = loadConfig(serverId, name);
config.setLongValue(value);
log.trace("Setting long value of key {} in server {}.", name, serverId);
return config;
}
@@ -138,6 +143,7 @@ public class ConfigManagementServiceBean implements ConfigManagementService {
public AConfig setStringValue(Long serverId, String name, String value) {
AConfig config = loadConfig(serverId, name);
config.setStringValue(value);
log.trace("Setting string value of key {} in server {}.", name, serverId);
return config;
}

View File

@@ -2,10 +2,12 @@ package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.models.database.ADefaultConfig;
import dev.sheldan.abstracto.core.repository.DefaultConfigRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class DefaultConfigManagementServiceBean implements DefaultConfigManagementService {
@Autowired
@@ -23,6 +25,7 @@ public class DefaultConfigManagementServiceBean implements DefaultConfigManageme
.name(key)
.stringValue(value)
.build();
log.trace("Creating default config entry with type string for key {}.", key);
}
defaultConfigRepository.save(build);
}
@@ -39,6 +42,7 @@ public class DefaultConfigManagementServiceBean implements DefaultConfigManageme
.name(key)
.longValue(value)
.build();
log.trace("Creating default config entry with type long for key {}.", key);
}
defaultConfigRepository.save(build);
}
@@ -55,6 +59,7 @@ public class DefaultConfigManagementServiceBean implements DefaultConfigManageme
.name(key)
.doubleValue(value)
.build();
log.trace("Creating default config entry with type double for key {}.", key);
}
defaultConfigRepository.save(build);
}

View File

@@ -5,6 +5,7 @@ import dev.sheldan.abstracto.core.exception.EmoteNotFoundInDbException;
import dev.sheldan.abstracto.core.models.database.AEmote;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.repository.EmoteRepository;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Emote;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -13,6 +14,7 @@ import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class EmoteManagementServiceBean implements EmoteManagementService {
@Autowired
@@ -56,6 +58,7 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
if(validateName) {
validateEmoteName(name);
}
log.info("Creating custom emote: id {}, animated {}, in server {}.", emoteId, animated, server.getId());
AEmote emoteToCreate = AEmote
.builder()
.custom(true)
@@ -81,6 +84,7 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
if(validateName) {
validateEmoteName(name);
}
log.info("Creating default inbuilt emote {} in server {}.", emoteKey, server.getId());
AEmote emoteToCreate = AEmote
.builder()
.custom(false)
@@ -113,6 +117,8 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
emote = this.createCustomEmote(name, emoteKey, emoteId, animated, server, true);
} else {
emote = emoteOptional.get();
log.trace("Setting existing emote (a: {}, c: {}, id: {}, discord id: {}) to new custom emote configuration: new id {}, animated {}.",
emote.getAnimated(), emote.getCustom(), emote.getId(), emote.getEmoteId(), emoteId, animated);
emote.setEmoteKey(emoteKey);
emote.setEmoteId(emoteId);
emote.setAnimated(animated);
@@ -124,20 +130,7 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
@Override
public AEmote setEmoteToCustomEmote(String name, Emote emote, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
AEmote emoteBeingSet;
Optional<AEmote> emoteOptional = loadEmoteByName(name, serverId);
if(!emoteOptional.isPresent()) {
emoteBeingSet = this.createCustomEmote(name, emote.getName(), emote.getIdLong(), emote.isAnimated(), server, true);
} else {
emoteBeingSet = emoteOptional.get();
emoteBeingSet.setCustom(true);
emoteBeingSet.setEmoteId(emote.getIdLong());
emoteBeingSet.setAnimated(emote.isAnimated());
emoteBeingSet.setEmoteKey(emote.getName());
repository.save(emoteBeingSet);
}
return emoteBeingSet;
return setEmoteToCustomEmote(name, emote.getName(), emote.getIdLong(), emote.isAnimated(), serverId);
}
@Override
@@ -149,8 +142,11 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
emoteBeingSet = this.createDefaultEmote(name, emoteKey, server, true);
} else {
emoteBeingSet = emoteOptional.get();
log.trace("Setting existing emote (a: {}, c: {}, id: {}, discord id: {}) to new default emote {}.",
emoteBeingSet.getAnimated(), emoteBeingSet.getCustom(), emoteBeingSet.getId(), emoteBeingSet.getEmoteId(), emoteKey);
emoteBeingSet.setEmoteKey(emoteKey);
emoteBeingSet.setCustom(false);
emoteBeingSet.setAnimated(false);
repository.save(emoteBeingSet);
}
return emoteBeingSet;
@@ -164,10 +160,14 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
} else {
AEmote emoteBeingSet = emoteOptional.get();
if(fakeEmote.getCustom()) {
log.trace("Setting existing emote (a: {}, c: {}, id: {}, discord id: {}) to new custom emote configuration: new id {}, animated {}.",
emoteBeingSet.getAnimated(), emoteBeingSet.getCustom(), emoteBeingSet.getId(), emoteBeingSet.getEmoteId(), fakeEmote.getEmoteId(), fakeEmote.getAnimated());
emoteBeingSet.setCustom(fakeEmote.getCustom());
emoteBeingSet.setEmoteId(fakeEmote.getEmoteId());
emoteBeingSet.setEmoteKey(fakeEmote.getEmoteKey());
} else {
log.trace("Setting existing emote (a: {}, c: {}, id: {}, discord id: {}) to new default emote {}.",
emoteBeingSet.getAnimated(), emoteBeingSet.getCustom(), emoteBeingSet.getId(), emoteBeingSet.getEmoteId(), fakeEmote.getEmoteKey());
emoteBeingSet.setCustom(false);
emoteBeingSet.setEmoteKey(fakeEmote.getEmoteKey());
}
@@ -197,6 +197,7 @@ public class EmoteManagementServiceBean implements EmoteManagementService {
@Override
public void deleteEmote(AEmote aEmote) {
log.info("Deleting emote with id {}", aEmote.getId());
repository.delete(aEmote);
}

View File

@@ -5,12 +5,14 @@ import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.models.database.AFeatureFlag;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.repository.FeatureFlagRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class FeatureFlagManagementServiceBean implements FeatureFlagManagementService {
@Autowired
@@ -36,6 +38,7 @@ public class FeatureFlagManagementServiceBean implements FeatureFlagManagementSe
.feature(feature)
.server(server)
.build();
log.info("Creating new feature flag for feature {} in server {} with value {}.", feature.getKey(), server.getId(), newValue);
repository.save(featureFlag);
return featureFlag;
}
@@ -59,15 +62,15 @@ public class FeatureFlagManagementServiceBean implements FeatureFlagManagementSe
@Override
public AFeatureFlag setFeatureFlagValue(AFeature feature, Long serverId, Boolean newValue) {
AFeatureFlag featureFlag = getFeatureFlag(feature, serverId);
featureFlag.setEnabled(newValue);
return featureFlag;
AServer server = serverManagementService.loadOrCreate(serverId);
return setFeatureFlagValue(feature, server, newValue);
}
@Override
public AFeatureFlag setFeatureFlagValue(AFeature feature, AServer server, Boolean newValue) {
AFeatureFlag featureFlag = getFeatureFlag(feature, server);
featureFlag.setEnabled(newValue);
log.info("Setting feature flag for feature {} in server {} to value {}.", feature.getKey(), server.getId(), newValue);
return featureFlag;
}
}

View File

@@ -3,10 +3,12 @@ package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.repository.FeatureRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class FeatureManagementServiceBean implements FeatureManagementService {
@Autowired
@@ -19,6 +21,7 @@ public class FeatureManagementServiceBean implements FeatureManagementService {
.key(key)
.build();
featureRepository.save(feature);
log.info("Creating new feature {}.", key);
return feature;
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.exception.PostTargetNotValidException;
import dev.sheldan.abstracto.core.exception.ServerChannelConflictException;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.PostTarget;
@@ -32,37 +33,42 @@ public class PostTargetManagementBean implements PostTargetManagement {
private DefaultPostTargetManagementService defaultPostTargetManagementService;
@Override
public PostTarget createPostTarget(String name, AServer server, AChannel targetChannel) {
public PostTarget createPostTarget(String name, AChannel targetChannel) {
if(!postTargetService.validPostTarget(name)) {
throw new PostTargetNotValidException(name, defaultPostTargetManagementService.getDefaultPostTargetKeys());
}
log.info("Creating post target {} pointing towards {}", name, targetChannel);
PostTarget build = PostTarget.builder().name(name).channelReference(targetChannel).serverReference(server).build();
log.info("Creating post target {} pointing towards {} on server {}.", name, targetChannel.getId(), targetChannel.getServer().getId());
PostTarget build = PostTarget.builder().name(name).channelReference(targetChannel).serverReference(targetChannel.getServer()).build();
postTargetRepository.save(build);
return build;
}
@Override
public PostTarget createOrUpdate(String name, AServer server, AChannel targetChannel) {
PostTarget existing = postTargetRepository.findPostTargetByNameAndServerReference(name, server);
public PostTarget createOrUpdate(String name, AChannel targetChannel) {
PostTarget existing = postTargetRepository.findPostTargetByNameAndServerReference(name, targetChannel.getServer());
if(existing == null){
return this.createPostTarget(name, server, targetChannel);
return this.createPostTarget(name, targetChannel);
} else {
return this.updatePostTarget(existing, server, targetChannel);
return this.updatePostTarget(existing, targetChannel);
}
}
@Override
public PostTarget createOrUpdate(String name, AServer server, Long channelId) {
AChannel dbChannel = channelManagementService.loadChannel(channelId);
return createOrUpdate(name, server, dbChannel);
if(!dbChannel.getServer().getId().equals(server.getId())) {
throw new ServerChannelConflictException(server.getId(), channelId);
}
return createOrUpdate(name, dbChannel);
}
@Override
public PostTarget createOrUpdate(String name, Long serverId, Long channelId) {
AChannel dbChannel = channelManagementService.loadChannel(channelId);
AServer dbServer = serverManagementService.loadOrCreate(serverId);
return createOrUpdate(name, dbServer, dbChannel);
if(!dbChannel.getServer().getId().equals(serverId)) {
throw new ServerChannelConflictException(serverId, channelId);
}
return createOrUpdate(name, dbChannel);
}
@Override
@@ -88,8 +94,9 @@ public class PostTargetManagementBean implements PostTargetManagement {
}
@Override
public PostTarget updatePostTarget(PostTarget target, AServer server, AChannel newTargetChannel) {
public PostTarget updatePostTarget(PostTarget target, AChannel newTargetChannel) {
target.setChannelReference(newTargetChannel);
log.info("Setting post target {} pointing towards {} on server {}.", target.getName(), newTargetChannel.getId(), newTargetChannel.getServer().getId());
return target;
}

View File

@@ -4,12 +4,14 @@ import dev.sheldan.abstracto.core.exception.RoleNotFoundInDBException;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.repository.RoleRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
@Slf4j
public class RoleManagementServiceBean implements RoleManagementService {
@Autowired
@@ -23,6 +25,8 @@ public class RoleManagementServiceBean implements RoleManagementService {
.server(server)
.deleted(false)
.build();
server.getRoles().add(build);
log.info("Creating role {} in server {}.", id, server.getId());
return repository.save(build);
}
@@ -38,6 +42,7 @@ public class RoleManagementServiceBean implements RoleManagementService {
@Override
public void markDeleted(ARole role) {
log.info("Marking role {} in server {} as deleted.", role.getId(), role.getServer().getId());
role.setDeleted(true);
}
}

View File

@@ -25,7 +25,9 @@ public class ServerManagementServiceBean implements ServerManagementService {
@Override
public AServer createServer(Long id) {
return repository.save(AServer.builder().id(id).build());
AServer newServer = AServer.builder().id(id).build();
log.info("Creating server with id {}.", id);
return repository.save(newServer);
}
@Override
@@ -46,6 +48,7 @@ public class ServerManagementServiceBean implements ServerManagementService {
@Override
public void addChannelToServer(AServer server, AChannel channel) {
log.info("Adding channel {} to server {}.", channel.getId(), server.getId());
server.getChannels().add(channel);
channel.setServer(server);
}

View File

@@ -65,6 +65,7 @@ public class UserInServerManagementServiceBean implements UserInServerManagement
@Override
public AUserInAServer createUserInServer(Long guildId, Long userId) {
log.info("Creating user {} in server {}.", userId, guildId);
AUserInAServer aUserInAServer = serverManagementService.addUserToServer(guildId, userId);
userInServerRepository.save(aUserInAServer);
return aUserInAServer;

View File

@@ -23,8 +23,8 @@ public class UserManagementServiceBean implements UserManagementService {
@Override
public AUser createUser(Long userId) {
log.info("Creating user {}", userId);
AUser aUser = AUser.builder().id(userId).build();
log.info("Creating user {}.", userId);
userRepository.save(aUser);
return aUser;
}

View File

@@ -25,6 +25,6 @@ public class CommandDisabledCondition implements CommandCondition {
if(!booleanResult) {
return ConditionResult.builder().result(true).exception(new CommandDisabledException()).build();
}
return ConditionResult.builder().result(true).reason("Command is disabled.").build();
return ConditionResult.builder().result(true).reason("Command is enabled.").build();
}
}

View File

@@ -10,6 +10,8 @@ import dev.sheldan.abstracto.core.command.service.management.CommandManagementSe
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.RoleService;
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.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -17,6 +19,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class CommandDisallowedCondition implements CommandCondition {
@@ -40,7 +43,9 @@ public class CommandDisallowedCondition implements CommandCondition {
return ConditionResult.builder().result(true).build();
}
for (ARole role : commandForServer.getAllowedRoles()) {
if (roleService.memberHasRole(context.getAuthor(), role)) {
Member author = context.getAuthor();
if (roleService.memberHasRole(author, role)) {
log.trace("Member {} is able to execute restricted command {}, because of role {}.", author.getIdLong(), aCommand.getName(), role.getId());
return ConditionResult.builder().result(true).build();
}
}

View File

@@ -7,10 +7,12 @@ import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.service.FeatureConfigService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class FeatureEnabledCondition implements CommandCondition {
@Autowired
@@ -29,6 +31,7 @@ public class FeatureEnabledCondition implements CommandCondition {
if(feature != null) {
featureFlagValue = featureFlagService.getFeatureFlagValue(feature, context.getGuild().getIdLong());
if(!featureFlagValue) {
log.trace("Feature {} is disabled, disallows command {} to be executed in guild {}.", feature.getKey(), command.getConfiguration().getName(), context.getGuild().getId());
FeatureDisabledException exception = new FeatureDisabledException(featureConfigService.getFeatureDisplayForFeature(command.getFeature()));
return ConditionResult.builder().result(false).exception(exception).build();
}

View File

@@ -10,6 +10,7 @@ import dev.sheldan.abstracto.core.command.service.management.CommandManagementSe
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -17,9 +18,9 @@ import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class ImmuneUserCondition implements CommandCondition {
@Autowired
private CommandInServerManagementService commandInServerManagementService;
@@ -41,6 +42,7 @@ public class ImmuneUserCondition implements CommandCondition {
Member member = any.get();
for (ARole role : commandForServer.getImmuneRoles()) {
if (roleService.memberHasRole(member, role)) {
log.trace("Member {} is immune against command {}, because of role {}.", member.getIdLong(), aCommand.getName(), role.getId());
ImmuneUserException exception = new ImmuneUserException(roleService.getRoleFromGuild(role));
return ConditionResult.builder().result(false).exception(exception).build();
}

View File

@@ -3,7 +3,7 @@ package dev.sheldan.abstracto.core.command.config;
import org.springframework.stereotype.Component;
@Component
public class AbstracatoModuleInterface implements ModuleInterface {
public class AbstractoModuleInterface implements ModuleInterface {
@Override
public ModuleInfo getInfo() {
return ModuleInfo.builder().name("default").description("Default module provided by abstracto").build();

View File

@@ -33,7 +33,7 @@ public class ContextConverter {
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.error("Failed to execute builder method", e);
}
throw new AbstractoRunTimeException("Failed to create model from context");
throw new AbstractoRunTimeException("Failed to create UserInitiatedServerContext from CommandContext.");
}
public static <T extends SlimUserInitiatedServerContext> SlimUserInitiatedServerContext slimFromCommandContext(CommandContext commandContext, Class<T> clazz) {
@@ -50,6 +50,6 @@ public class ContextConverter {
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.error("Failed to execute builder method", e);
}
throw new AbstractoRunTimeException("Failed to create model from context");
throw new AbstractoRunTimeException("Failed to create SlimUserInitiatedServerContext from CommandContext");
}
}

View File

@@ -8,7 +8,7 @@ import java.util.List;
public interface ChannelGroupCommandManagementService {
void setCommandInGroupTo(ACommand command, AChannelGroup group, Boolean enabled);
AChannelGroupCommand createCommandInGroupTo(ACommand command, AChannelGroup group);
AChannelGroupCommand createCommandInGroup(ACommand command, AChannelGroup group);
AChannelGroupCommand getChannelGroupCommand(ACommand command, AChannelGroup group);
List<AChannelGroupCommand> getAllGroupCommandsForCommand(ACommand command);
}

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.models.exception.ServerChannelConflictExceptionModel;
import dev.sheldan.abstracto.templating.Templatable;
public class ServerChannelConflictException extends AbstractoRunTimeException implements Templatable {
private final ServerChannelConflictExceptionModel model;
public ServerChannelConflictException(Long serverId, Long channelId) {
super("Given channel was not part of the assumed server.");
this.model = ServerChannelConflictExceptionModel.builder().channelId(channelId).serverId(serverId).build();
}
@Override
public String getTemplateName() {
return "server_channel_conflict_exception";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.core.models.exception;
import lombok.Builder;
import lombok.Getter;
import java.io.Serializable;
@Getter
@Builder
public class ServerChannelConflictExceptionModel implements Serializable {
private final Long serverId;
private final Long channelId;
}

View File

@@ -5,7 +5,8 @@ import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
import lombok.Getter;
import lombok.experimental.SuperBuilder;
@Getter @SuperBuilder
@Getter
@SuperBuilder
public class EchoModel extends UserInitiatedServerContext {
private String text;
}

View File

@@ -4,7 +4,8 @@ import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
import lombok.Getter;
import lombok.experimental.SuperBuilder;
@Getter @SuperBuilder
@Getter
@SuperBuilder
public class PingModel extends UserInitiatedServerContext {
private Long latency;
}

View File

@@ -7,14 +7,14 @@ import dev.sheldan.abstracto.core.models.database.PostTarget;
import java.util.List;
public interface PostTargetManagement {
PostTarget createPostTarget(String name, AServer server, AChannel targetChanel);
PostTarget createOrUpdate(String name, AServer server, AChannel targetChannel);
PostTarget createPostTarget(String name, AChannel targetChanel);
PostTarget createOrUpdate(String name, AChannel targetChannel);
PostTarget createOrUpdate(String name, AServer server, Long channelId);
PostTarget createOrUpdate(String name, Long serverId, Long channelId);
PostTarget getPostTarget(String name, AServer server);
PostTarget getPostTarget(String name, Long serverId);
Boolean postTargetExists(String name, AServer server);
boolean postTargetExists(String name, Long serverId);
PostTarget updatePostTarget(PostTarget target, AServer server, AChannel newTargetChannel);
PostTarget updatePostTarget(PostTarget target, AChannel newTargetChannel);
List<PostTarget> getPostTargetsInServer(AServer server);
}

View File

@@ -7,6 +7,6 @@ public class ChannelUtils {
}
public static String buildChannelUrl(Long serverId, Long channelId) {
return String.format("https://discordapp.com/channels/%s/%s/", serverId, channelId);
return String.format("https://discord.com/channels/%s/%s/", serverId, channelId);
}
}

View File

@@ -49,6 +49,6 @@ public class ContextUtils {
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
log.error("Failed to execute builder method", e);
}
throw new AbstractoRunTimeException("Failed to create model from message");
throw new AbstractoRunTimeException("Failed to create UserInitiatedServerContext from message");
}
}

View File

@@ -7,6 +7,6 @@ public class MessageUtils {
}
public static String buildMessageUrl(Long serverId, Long channelId, Long messageId) {
return String.format("https://discordapp.com/channels/%s/%s/%s", serverId, channelId, messageId);
return String.format("https://discord.com/channels/%s/%s/%s", serverId, channelId, messageId);
}
}