added the concept of commands in server, to have a separate config for commands within a server

added server config listener, to create such commands
moved the command and feature creation to separate spring listener (they are dependant, a mechanism for dependencies is needed)
added a feature flag to the command table, so we know what the feature of a command is
added ability to restrict commands to certain roles/remove the restriction
added ability to make some roles not affected by a command/remove the immunity, this works by retrieving the first member from the command parameters, and checking if the member has the said role
commands in a server now have a restricted flag to indicate, if the role checks should be in effect (only affects role-to-execute restriction)
fixed initial prefix config
added the immune user check only to commands most likely needing it
This commit is contained in:
Sheldan
2020-04-27 17:32:33 +02:00
parent 05aa0815d6
commit e08086b6a9
59 changed files with 1110 additions and 72 deletions

View File

@@ -71,10 +71,10 @@ public class CommandReceivedHandler extends ListenerAdapter {
@Async
@Transactional
public void onMessageReceived(@Nonnull MessageReceivedEvent event) {
if(!commandManager.isCommand(event.getMessage())) {
if(!event.isFromGuild()) {
return;
}
if(!event.isFromGuild()) {
if(!commandManager.isCommand(event.getMessage())) {
return;
}
CommandContext.CommandContextBuilder commandContextBuilder = CommandContext.builder()

View File

@@ -1,7 +1,9 @@
package dev.sheldan.abstracto.core.command.config;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
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 org.springframework.beans.factory.annotation.Autowired;
@@ -16,13 +18,17 @@ public class CommandConfigListener implements ServerConfigListener {
private List<Command> commandList;
@Autowired
private CommandService commandService;
private CommandInServerManagementService commandInServerManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Override
public void updateServerConfig(AServer server) {
commandList.forEach(command -> {
if(!commandService.doesCommandExist(command.getConfiguration().getName())) {
commandService.createCommand(command.getConfiguration().getName(), command.getConfiguration().getModule());
ACommand aCommand = commandManagementService.findCommandByName(command.getConfiguration().getName());
if(!commandInServerManagementService.doesCommandExistInServer(aCommand, server)) {
commandInServerManagementService.crateCommandInServer(aCommand, server);
}
});
}

View File

@@ -0,0 +1,46 @@
package dev.sheldan.abstracto.core.command.config;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Component
public class CommandCreationListener {
@Autowired
private List<Command> commandList;
@Autowired
private CommandService commandService;
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private FeatureManagementService featureManagementService;
@EventListener
@Transactional
public void handleContextRefreshEvent(ContextRefreshedEvent ctxStartEvt) {
featureFlagService.getAllFeatureDisplays().forEach((featureFlagKey) -> {
String featureKey = featureFlagKey.getFeature().getKey();
if(!featureManagementService.featureExists(featureKey)) {
featureManagementService.createFeature(featureKey);
}
});
commandList.forEach(command -> {
if(!commandService.doesCommandExist(command.getConfiguration().getName())) {
commandService.createCommand(command.getConfiguration().getName(), command.getConfiguration().getModule(), command.getFeature());
}
});
}
}

View File

@@ -0,0 +1,12 @@
package dev.sheldan.abstracto.core.command.repository;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.models.database.ACommandInAServer;
import dev.sheldan.abstracto.core.models.database.AServer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CommandInServerRepository extends JpaRepository<ACommandInAServer, Long> {
ACommandInAServer findByServerReferenceAndCommandReference(AServer server, ACommand command);
}

View File

@@ -1,9 +1,16 @@
package dev.sheldan.abstracto.core.command.service;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.models.database.ACommandInAServer;
import dev.sheldan.abstracto.core.command.models.database.AModule;
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.command.service.management.ModuleManagementService;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -16,10 +23,17 @@ public class CommandServiceBean implements CommandService {
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private FeatureManagementService featureManagementService;
@Autowired
private CommandInServerManagementService commandInServerManagementService;
@Override
public ACommand createCommand(String name, String moduleName) {
public ACommand createCommand(String name, String moduleName, FeatureEnum featureEnum) {
AModule module = moduleManagementService.getOrCreate(moduleName);
return commandManagementService.createCommand(name, module);
AFeature feature = featureManagementService.getFeature(featureEnum.getKey());
return commandManagementService.createCommand(name, module, feature);
}
@Override
@@ -27,5 +41,47 @@ public class CommandServiceBean implements CommandService {
return commandManagementService.doesCommandExist(name);
}
@Override
public void allowCommandForRole(ACommand aCommand, ARole role) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer());
if(!commandForServer.getAllowedRoles().contains(role)) {
commandForServer.getAllowedRoles().add(role);
}
commandForServer.setRestricted(true);
}
@Override
public void makeRoleImmuneForCommand(ACommand aCommand, ARole role) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer());
if(!commandForServer.getImmuneRoles().contains(role)) {
commandForServer.getImmuneRoles().add(role);
}
}
@Override
public void makeRoleAffectedByCommand(ACommand aCommand, ARole role) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer());
commandForServer.getImmuneRoles().remove(role);
}
@Override
public void restrictCommand(ACommand aCommand, AServer server) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, server);
commandForServer.setRestricted(true);
}
@Override
public void unRestrictCommand(ACommand aCommand, AServer server) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, server);
commandForServer.setRestricted(false);
}
@Override
public void disAllowCommandForRole(ACommand aCommand, ARole role) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer());
commandForServer.setRestricted(true);
commandForServer.getAllowedRoles().remove(role);
}
}

View File

@@ -0,0 +1,37 @@
package dev.sheldan.abstracto.core.command.service.management;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CommandInServerManagementServiceBean implements CommandInServerManagementService {
@Autowired
private CommandInServerRepository repository;
@Override
public ACommandInAServer crateCommandInServer(ACommand command, AServer server) {
ACommandInAServer commandInAServer = ACommandInAServer
.builder()
.commandReference(command)
.serverReference(server)
.restricted(false)
.build();
repository.save(commandInAServer);
return commandInAServer;
}
@Override
public boolean doesCommandExistInServer(ACommand command, AServer server) {
return getCommandForServer(command, server) != null;
}
@Override
public ACommandInAServer getCommandForServer(ACommand command, AServer server) {
return repository.findByServerReferenceAndCommandReference(server, command);
}
}

View File

@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.core.command.service.management;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -15,18 +16,23 @@ public class CommandManagementServiceBean implements CommandManagementService {
@Autowired
private CommandRepository commandRepository;
@Autowired
private FeatureManagementService featureManagementService;
@Override
public ACommand createCommand(String name, String moduleName) {
public ACommand createCommand(String name, String moduleName, String featureName) {
AModule module = moduleManagementService.findModuleByName(moduleName);
return createCommand(name, module);
AFeature feature = featureManagementService.getFeature(featureName);
return createCommand(name, module, feature);
}
@Override
public ACommand createCommand(String name, AModule module) {
public ACommand createCommand(String name, AModule module, AFeature feature) {
ACommand command = ACommand
.builder()
.name(name)
.module(module)
.feature(feature)
.build();
commandRepository.save(command);
return command;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -16,7 +16,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class AddToChannelGroup implements Command {
public class AddToChannelGroup extends AbstractConditionableCommand {
@Autowired

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -15,7 +15,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class CreateChannelGroup implements Command {
public class CreateChannelGroup extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -15,7 +15,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class DeleteChannelGroup implements Command {
public class DeleteChannelGroup extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -15,7 +16,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class DisableCommand implements Command {
public class DisableCommand extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;
@@ -46,4 +47,11 @@ public class DisableCommand implements Command {
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
@Override
public List<CommandCondition> getConditions() {
List<CommandCondition> conditions = super.getConditions();
conditions.remove(commandDisabledCondition);
return conditions;
}
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -15,7 +16,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class EnableCommand implements Command {
public class EnableCommand extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;
@@ -46,4 +47,11 @@ public class EnableCommand implements Command {
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
@Override
public List<CommandCondition> getConditions() {
List<CommandCondition> conditions = super.getConditions();
conditions.remove(commandDisabledCondition);
return conditions;
}
}

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -25,7 +25,7 @@ import java.util.List;
import java.util.Optional;
@Component
public class ListChannelGroups implements Command {
public class ListChannelGroups extends AbstractConditionableCommand {
@Autowired
private TemplateService templateService;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.*;
@@ -22,7 +22,7 @@ import java.util.List;
@Service
@Slf4j
public class PostTarget implements Command {
public class PostTarget extends AbstractConditionableCommand {
public static final String POST_TARGET_NO_TARGET_TEMPLATE = "posttarget_no_target";
public static final String POST_TARGET_INVALID_TARGET_TEMPLATE = "posttarget_invalid_target";

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -16,7 +16,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class RemoveFromChannelGroup implements Command {
public class RemoveFromChannelGroup extends AbstractConditionableCommand {
@Autowired

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.config;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
@@ -15,7 +15,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class SetNumber implements Command {
public class SetNumber extends AbstractConditionableCommand {
@Autowired
private ConfigService configService;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.config;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
@@ -15,7 +15,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class SetPrefix implements Command {
public class SetPrefix extends AbstractConditionableCommand {
@Autowired
private ConfigService configService;

View File

@@ -0,0 +1,72 @@
package dev.sheldan.abstracto.core.commands.config.features;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class Allow extends AbstractConditionableCommand {
@Autowired
private FeatureManagementService featureManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private CommandService commandService;
@Autowired
private RoleManagementService roleManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
String name = (String) commandContext.getParameters().getParameters().get(0);
if(featureManagementService.featureExists(name)) {
AFeature feature = featureManagementService.getFeature(name);
feature.getCommands().forEach(command -> {
commandService.unRestrictCommand(command, commandContext.getUserInitiatedContext().getServer());
});
} else if(commandManagementService.doesCommandExist(name)) {
ACommand command = commandManagementService.findCommandByName(name);
commandService.unRestrictCommand(command, commandContext.getUserInitiatedContext().getServer());
} else {
return CommandResult.fromError("No Feature/Command with that name");
}
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter featureName = Parameter.builder().name("feature|commandName").type(String.class).description("The command/feature name to allow for anyone to execute.").build();
List<Parameter> parameters = Arrays.asList(featureName);
return CommandConfiguration.builder()
.name("allow")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.description("Removes the role restrictions from a command.")
.causesReaction(true)
.build();
}
@Override
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,76 @@
package dev.sheldan.abstracto.core.commands.config.features;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class AllowRole extends AbstractConditionableCommand {
@Autowired
private FeatureManagementService featureManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private CommandService commandService;
@Autowired
private RoleManagementService roleManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
String name = (String) commandContext.getParameters().getParameters().get(0);
Long roleId = (Long) commandContext.getParameters().getParameters().get(1);
ARole role = roleManagementService.findRole(roleId);
if(featureManagementService.featureExists(name)) {
AFeature feature = featureManagementService.getFeature(name);
feature.getCommands().forEach(command -> {
commandService.allowCommandForRole(command, role);
});
} else if(commandManagementService.doesCommandExist(name)) {
ACommand command = commandManagementService.findCommandByName(name);
commandService.allowCommandForRole(command, role);
} else {
return CommandResult.fromError("No Feature/Command with that name");
}
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter featureName = Parameter.builder().name("feature|commandName").type(String.class).description("The command/feature the role should be able to execute.").build();
Parameter role = Parameter.builder().name("roleId").type(Long.class).description("The roleId to allow it for.").build();
List<Parameter> parameters = Arrays.asList(featureName, role);
return CommandConfiguration.builder()
.name("allowRole")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.description("Allows roles to execute commands in features or commands directly")
.causesReaction(true)
.build();
}
@Override
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,76 @@
package dev.sheldan.abstracto.core.commands.config.features;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class DisAllowRole extends AbstractConditionableCommand {
@Autowired
private FeatureManagementService featureManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private CommandService commandService;
@Autowired
private RoleManagementService roleManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
String name = (String) commandContext.getParameters().getParameters().get(0);
Long roleId = (Long) commandContext.getParameters().getParameters().get(1);
ARole role = roleManagementService.findRole(roleId);
if(featureManagementService.featureExists(name)) {
AFeature feature = featureManagementService.getFeature(name);
feature.getCommands().forEach(command -> {
commandService.disAllowCommandForRole(command, role);
});
} else if(commandManagementService.doesCommandExist(name)) {
ACommand command = commandManagementService.findCommandByName(name);
commandService.disAllowCommandForRole(command, role);
} else {
return CommandResult.fromError("No Feature/Command with that name");
}
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter featureName = Parameter.builder().name("feature|commandName").type(String.class).description("The command/feature the role should not be able to execute.").build();
Parameter role = Parameter.builder().name("roleId").type(Long.class).description("The roleId to disallow it for.").build();
List<Parameter> parameters = Arrays.asList(featureName, role);
return CommandConfiguration.builder()
.name("disAllowRole")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.description("Disallows roles to execute commands in features or commands directly.")
.causesReaction(true)
.build();
}
@Override
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.commands.config.features;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -20,7 +21,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class Disable implements Command {
public class Disable extends AbstractConditionableCommand {
@Autowired
private FeatureFlagService featureFlagService;
@@ -64,4 +65,11 @@ public class Disable implements Command {
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
@Override
public List<CommandCondition> getConditions() {
List<CommandCondition> conditions = super.getConditions();
conditions.remove(featureEnabledCondition);
return conditions;
}
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.commands.config.features;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.condition.CommandCondition;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -20,7 +21,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class Enable implements Command {
public class Enable extends AbstractConditionableCommand {
@Autowired
private FeatureFlagService featureFlagService;
@@ -63,4 +64,11 @@ public class Enable implements Command {
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
@Override
public List<CommandCondition> getConditions() {
List<CommandCondition> conditions = super.getConditions();
conditions.remove(featureEnabledCondition);
return conditions;
}
}

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.config.features;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -21,7 +21,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class Features implements Command {
public class Features extends AbstractConditionableCommand {
@Autowired
private FeatureFlagManagementService featureFlagManagementService;

View File

@@ -0,0 +1,76 @@
package dev.sheldan.abstracto.core.commands.config.features;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class MakeAffected extends AbstractConditionableCommand {
@Autowired
private FeatureManagementService featureManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private CommandService commandService;
@Autowired
private RoleManagementService roleManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
String name = (String) commandContext.getParameters().getParameters().get(0);
Long roleId = (Long) commandContext.getParameters().getParameters().get(1);
ARole role = roleManagementService.findRole(roleId);
if(featureManagementService.featureExists(name)) {
AFeature feature = featureManagementService.getFeature(name);
feature.getCommands().forEach(command -> {
commandService.makeRoleAffectedByCommand(command, role);
});
} else if(commandManagementService.doesCommandExist(name)) {
ACommand command = commandManagementService.findCommandByName(name);
commandService.makeRoleAffectedByCommand(command, role);
} else {
return CommandResult.fromError("No Feature/Command with that name");
}
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter featureName = Parameter.builder().name("feature|commandName").type(String.class).description("The command/feature name to make the role affected by.").build();
Parameter role = Parameter.builder().name("roleId").type(Long.class).description("The roleId to make affected.").build();
List<Parameter> parameters = Arrays.asList(featureName, role);
return CommandConfiguration.builder()
.name("makeAffected")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.description("Makes a role vulnerable to be affected by certain commands.")
.causesReaction(true)
.build();
}
@Override
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,76 @@
package dev.sheldan.abstracto.core.commands.config.features;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class MakeImmune extends AbstractConditionableCommand {
@Autowired
private FeatureManagementService featureManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private CommandService commandService;
@Autowired
private RoleManagementService roleManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
String name = (String) commandContext.getParameters().getParameters().get(0);
Long roleId = (Long) commandContext.getParameters().getParameters().get(1);
ARole role = roleManagementService.findRole(roleId);
if(featureManagementService.featureExists(name)) {
AFeature feature = featureManagementService.getFeature(name);
feature.getCommands().forEach(command -> {
commandService.makeRoleImmuneForCommand(command, role);
});
} else if(commandManagementService.doesCommandExist(name)) {
ACommand command = commandManagementService.findCommandByName(name);
commandService.makeRoleImmuneForCommand(command, role);
} else {
return CommandResult.fromError("No Feature/Command with that name");
}
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter featureName = Parameter.builder().name("feature|commandName").type(String.class).description("The command/feature name to make the role immune for.").build();
Parameter role = Parameter.builder().name("roleId").type(Long.class).description("The roleId to make immune.").build();
List<Parameter> parameters = Arrays.asList(featureName, role);
return CommandConfiguration.builder()
.name("makeImmune")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.description("Makes a role immune to be affected by certain commands.")
.causesReaction(true)
.build();
}
@Override
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,72 @@
package dev.sheldan.abstracto.core.commands.config.features;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleInterface;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.config.features.CoreFeatures;
import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class Restrict extends AbstractConditionableCommand {
@Autowired
private FeatureManagementService featureManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private CommandService commandService;
@Autowired
private RoleManagementService roleManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
String name = (String) commandContext.getParameters().getParameters().get(0);
if(featureManagementService.featureExists(name)) {
AFeature feature = featureManagementService.getFeature(name);
feature.getCommands().forEach(command -> {
commandService.restrictCommand(command, commandContext.getUserInitiatedContext().getServer());
});
} else if(commandManagementService.doesCommandExist(name)) {
ACommand command = commandManagementService.findCommandByName(name);
commandService.restrictCommand(command, commandContext.getUserInitiatedContext().getServer());
} else {
return CommandResult.fromError("No Feature/Command with that name");
}
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter featureName = Parameter.builder().name("feature|commandName").type(String.class).description("The command/feature name to restrict.").build();
List<Parameter> parameters = Arrays.asList(featureName);
return CommandConfiguration.builder()
.name("restrict")
.module(ConfigModuleInterface.CONFIG)
.parameters(parameters)
.description("Allows to restrict commands/features. Meaning, not all roles can execute it.")
.causesReaction(true)
.build();
}
@Override
public FeatureEnum getFeature() {
return CoreFeatures.CORE_FEATURE;
}
}

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.utility;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
@@ -17,7 +17,7 @@ import java.util.ArrayList;
import java.util.List;
@Service
public class Echo implements Command {
public class Echo extends AbstractConditionableCommand {
private static final String TEMPLATE_NAME = "echo_response";

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.commands.utility;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
@@ -16,7 +16,7 @@ import java.util.Arrays;
import java.util.List;
@Component
public class SetEmote implements Command {
public class SetEmote extends AbstractConditionableCommand {
@Autowired
private EmoteManagementService emoteManagementService;

View File

@@ -1,6 +1,8 @@
package dev.sheldan.abstracto.core.config;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.listener.ServerConfigListener;
import dev.sheldan.abstracto.core.models.database.AFeature;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import dev.sheldan.abstracto.core.service.management.FeatureFlagManagementService;
@@ -20,6 +22,9 @@ public class FeatureFlagListener implements ServerConfigListener {
@Autowired
private FeatureFlagManagementService service;
@Autowired
private FeatureManagementService featureManagementService;
@Autowired
private Environment environment;
@@ -27,9 +32,11 @@ public class FeatureFlagListener implements ServerConfigListener {
public void updateServerConfig(AServer server) {
log.info("Setting up feature flags if necessary.");
featureFlagService.getAllFeatureDisplays().forEach((featureFlagKey) -> {
boolean featureFlagValue = BooleanUtils.toBoolean(environment.getProperty("abstracto.features." + featureFlagKey.getFeature().getKey(), "false"));
if(!service.getFeatureFlag(featureFlagKey.getFeature(), server.getId()).isPresent()) {
service.createFeatureFlag(featureFlagKey.getFeature(), server.getId(), featureFlagValue);
String featureKey = featureFlagKey.getFeature().getKey();
AFeature feature = featureManagementService.getFeature(featureKey);
boolean featureFlagValue = BooleanUtils.toBoolean(environment.getProperty("abstracto.features." + featureKey, "false"));
if(!service.getFeatureFlag(feature, server.getId()).isPresent()) {
service.createFeatureFlag(feature, server.getId(), featureFlagValue);
}
});
}

View File

@@ -0,0 +1,26 @@
package dev.sheldan.abstracto.core.config;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.service.FeatureFlagService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
// TODO runtime dependencies, features are required by commands, race condition
@Component
@Slf4j
public class FeatureListener {
@Autowired
private FeatureFlagService featureFlagService;
@Autowired
private FeatureManagementService featureManagementService;
@EventListener
public void handleContextRefreshEvent(ContextRefreshedEvent ctxStartEvt) {
}
}

View File

@@ -18,7 +18,7 @@ public class FeatureFlagConverter {
private FeatureFlagService featureFlagService;
public FeatureFlagDisplay fromAFeatureFlag(AFeatureFlag featureFlag) {
FeatureEnum featureEnum = featureFlagService.getFeatureEnum(featureFlag.getKey());
FeatureEnum featureEnum = featureFlagService.getFeatureEnum(featureFlag.getFeature().getKey());
FeatureDisplay forFeature = featureFlagService.getFeatureDisplayforFeature(featureEnum);
return FeatureFlagDisplay
.builder()

View File

@@ -12,7 +12,7 @@ public class CoreServiceConfigListener implements ServerConfigListener {
@Autowired
private ConfigManagementService configManagementService;
@Value("§{abstracto.prefix}")
@Value("${abstracto.prefix}")
private String prefix;
@Override

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.core.repository;
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 org.springframework.data.jpa.repository.JpaRepository;
@@ -7,6 +8,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface FeatureFlagRepository extends JpaRepository<AFeatureFlag, Long> {
AFeatureFlag findByServerAndKey(AServer server, String key);
AFeatureFlag findByServerAndFeature(AServer server, AFeature key);
List<AFeatureFlag> findAllByServer(AServer server);
}

View File

@@ -0,0 +1,10 @@
package dev.sheldan.abstracto.core.repository;
import dev.sheldan.abstracto.core.models.database.AFeature;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface FeatureRepository extends JpaRepository<AFeature, Long> {
AFeature findByKey(String key);
}

View File

@@ -12,7 +12,9 @@ import net.dv8tion.jda.api.entities.Role;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Component
@Slf4j
@@ -81,6 +83,11 @@ public class RoleServiceBean implements RoleService {
}
}
@Override
public List<Role> getRolesFromGuild(List<ARole> roles) {
return roles.stream().map(this::getRoleFromGuild).collect(Collectors.toList());
}
@Override
public boolean memberHasRole(Member member, Role role) {
return member.getRoles().stream().anyMatch(role1 -> role1.getIdLong() == role.getIdLong());

View File

@@ -1,6 +1,8 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
import dev.sheldan.abstracto.core.config.FeatureEnum;
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;
@@ -19,32 +21,38 @@ public class FeatureFlagManagementServiceBean implements FeatureFlagManagementSe
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private FeatureManagementService featureManagementService;
@Override
public void createFeatureFlag(FeatureEnum key, Long serverId, Boolean newValue) {
public void createFeatureFlag(AFeature feature, Long serverId, Boolean newValue) {
AServer server = serverManagementService.loadOrCreate(serverId);
createFeatureFlag(key, server, newValue);
createFeatureFlag(feature, server, newValue);
}
@Override
public void createFeatureFlag(FeatureEnum key, AServer server, Boolean newValue) {
public void createFeatureFlag(AFeature feature, AServer server, Boolean newValue) {
AFeatureFlag featureFlag = AFeatureFlag
.builder()
.enabled(newValue)
.key(key.getKey())
.feature(feature)
.server(server)
.build();
repository.save(featureFlag);
}
@Override
public boolean getFeatureFlagValue(FeatureEnum key, Long serverId) {
Optional<AFeatureFlag> featureFlag = getFeatureFlag(key, serverId);
AFeature feature = featureManagementService.getFeature(key.getKey());
Optional<AFeatureFlag> featureFlag = getFeatureFlag(feature, serverId);
return featureFlag.isPresent() && featureFlag.get().isEnabled();
}
@Override
public void updateFeatureFlag(FeatureEnum key, Long serverId, Boolean newValue) {
Optional<AFeatureFlag> existing = getFeatureFlag(key, serverId);
AFeature feature = featureManagementService.getFeature(key.getKey());
Optional<AFeatureFlag> existing = getFeatureFlag(feature, serverId);
if(existing.isPresent()) {
AFeatureFlag flag = existing.get();
flag.setEnabled(newValue);
@@ -53,9 +61,9 @@ public class FeatureFlagManagementServiceBean implements FeatureFlagManagementSe
}
@Override
public Optional<AFeatureFlag> getFeatureFlag(FeatureEnum key, Long serverId) {
public Optional<AFeatureFlag> getFeatureFlag(AFeature feature, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
return Optional.ofNullable(repository.findByServerAndKey(server, key.getKey()));
return Optional.ofNullable(repository.findByServerAndFeature(server, feature));
}
@Override

View File

@@ -0,0 +1,34 @@
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class FeatureManagementServiceBean implements FeatureManagementService {
@Autowired
private FeatureRepository featureRepository;
@Override
public AFeature createFeature(String key) {
AFeature feature = AFeature
.builder()
.key(key)
.build();
featureRepository.save(feature);
return feature;
}
@Override
public boolean featureExists(String key) {
return getFeature(key) != null;
}
@Override
public AFeature getFeature(String key) {
return featureRepository.findByKey(key);
}
}

View File

@@ -0,0 +1 @@
The targeted user is immune against this command, because of the role: ${role.name}.

View File

@@ -0,0 +1 @@
You lack the necessary role to execute this command. One of the following is needed: <#list allowedRoles as role>${role.name}<#sep>,<#else>None configured.</#list>