mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-16 20:29:08 +00:00
[AB-307] enabling dependent features and including them into the setup wizard
this comes with the usual limitation, that dependent features must be referenced via importing
This commit is contained in:
@@ -13,18 +13,22 @@ import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.template.commands.EnableModel;
|
||||
import dev.sheldan.abstracto.core.models.template.commands.FeatureSwitchModel;
|
||||
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.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class DisableFeature extends AbstractConditionableCommand {
|
||||
@@ -43,26 +47,46 @@ public class DisableFeature extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
private static final String DISABLE_FEATURE_ALL_FEATURES_RESPONSE_TEMPLATE_KEY = "disableFeature_all_features_response";
|
||||
private static final String DISABLE_FEATURE_DEPENDENCIES_RESPONSE_TEMPLATE_KEY = "disableFeature_feature_dependencies_response";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
if (commandContext.getParameters().getParameters().isEmpty()) {
|
||||
EnableModel model = (EnableModel) ContextConverter.fromCommandContext(commandContext, EnableModel.class);
|
||||
FeatureSwitchModel model = (FeatureSwitchModel) ContextConverter.fromCommandContext(commandContext, FeatureSwitchModel.class);
|
||||
model.setFeatures(featureConfigService.getAllFeatures());
|
||||
String response = templateService.renderTemplate("disable_features_response", model, commandContext.getGuild().getIdLong());
|
||||
return channelService.sendTextToChannel(response, commandContext.getChannel())
|
||||
.thenApply(aVoid -> CommandResult.fromSuccess());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(DISABLE_FEATURE_ALL_FEATURES_RESPONSE_TEMPLATE_KEY, model, commandContext.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(message -> CommandResult.fromIgnored());
|
||||
} else {
|
||||
String flagKey = (String) commandContext.getParameters().getParameters().get(0);
|
||||
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(flagKey);
|
||||
featureFlagService.disableFeature(feature, commandContext.getGuild().getIdLong());
|
||||
List<FeatureConfig> featureDependencies = new ArrayList<>();
|
||||
if (feature.getDependantFeatures() != null) {
|
||||
AServer server = serverManagementService.loadServer(commandContext.getGuild());
|
||||
feature.getDependantFeatures().forEach(featureDisplay ->
|
||||
featureFlagService.disableFeature(featureDisplay, server)
|
||||
feature.getDependantFeatures().forEach(featureDisplay -> {
|
||||
if (featureFlagService.isFeatureEnabled(featureDisplay, server)) {
|
||||
featureFlagService.disableFeature(featureDisplay, server);
|
||||
featureDependencies.add(featureDisplay);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
if (featureDependencies.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(CommandResult.fromSuccess());
|
||||
} else {
|
||||
List<String> additionalFeatures = featureDependencies
|
||||
.stream()
|
||||
.map(featureDef -> featureDef.getFeature().getKey()).
|
||||
collect(Collectors.toList());
|
||||
FeatureSwitchModel model = (FeatureSwitchModel) ContextConverter.fromCommandContext(commandContext, FeatureSwitchModel.class);
|
||||
model.setFeatures(additionalFeatures);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(DISABLE_FEATURE_DEPENDENCIES_RESPONSE_TEMPLATE_KEY,
|
||||
model, commandContext.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(message -> CommandResult.fromIgnored());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,19 +14,23 @@ import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.models.FeatureValidationResult;
|
||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||
import dev.sheldan.abstracto.core.models.template.commands.EnableModel;
|
||||
import dev.sheldan.abstracto.core.models.template.commands.FeatureSwitchModel;
|
||||
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.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@@ -47,32 +51,52 @@ public class EnableFeature extends AbstractConditionableCommand {
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
private static final String ENABLE_FEATURE_DEPENDENCIES_RESPONSE_TEMPLATE_KEY = "enableFeature_feature_dependencies_response";
|
||||
private static final String ENABLE_FEATURE_ALL_FEATURES_RESPONSE = "enableFeature_all_features_response";
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
if(commandContext.getParameters().getParameters().isEmpty()) {
|
||||
EnableModel model = (EnableModel) ContextConverter.fromCommandContext(commandContext, EnableModel.class);
|
||||
FeatureSwitchModel model = (FeatureSwitchModel) ContextConverter.fromCommandContext(commandContext, FeatureSwitchModel.class);
|
||||
model.setFeatures(featureConfigService.getAllFeatures());
|
||||
String response = templateService.renderTemplate("enable_features_response", model, commandContext.getGuild().getIdLong());
|
||||
return channelService.sendTextToChannel(response, commandContext.getChannel())
|
||||
.thenApply(message -> CommandResult.fromSuccess());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(ENABLE_FEATURE_ALL_FEATURES_RESPONSE, model, commandContext.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(message -> CommandResult.fromIgnored());
|
||||
} else {
|
||||
String flagKey = (String) commandContext.getParameters().getParameters().get(0);
|
||||
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(flagKey);
|
||||
String featureKey = (String) commandContext.getParameters().getParameters().get(0);
|
||||
FeatureConfig feature = featureConfigService.getFeatureDisplayForFeature(featureKey);
|
||||
AServer server = serverManagementService.loadServer(commandContext.getUserInitiatedContext().getGuild().getIdLong());
|
||||
FeatureValidationResult featureSetup = featureConfigService.validateFeatureSetup(feature, server);
|
||||
if(Boolean.FALSE.equals(featureSetup.getValidationResult())) {
|
||||
log.info("Feature {} has failed the setup validation. Notifying user.", flagKey);
|
||||
log.info("Feature {} has failed the setup validation. Notifying user.", featureKey);
|
||||
channelService.sendTextToChannelNotAsync(templateService.renderTemplatable(featureSetup, commandContext.getGuild().getIdLong()),
|
||||
commandContext.getChannel());
|
||||
}
|
||||
featureFlagService.enableFeature(feature, server);
|
||||
List<FeatureConfig> featureDependencies = new ArrayList<>();
|
||||
if(feature.getRequiredFeatures() != null) {
|
||||
feature.getRequiredFeatures().forEach(featureDisplay -> {
|
||||
log.info("Also enabling required feature {}.", featureDisplay.getFeature().getKey());
|
||||
if(!featureFlagService.isFeatureEnabled(featureDisplay, server)) {
|
||||
featureFlagService.enableFeature(featureDisplay, server);
|
||||
featureDependencies.add(featureDisplay);
|
||||
}
|
||||
});
|
||||
}
|
||||
if(featureDependencies.isEmpty()) {
|
||||
return CompletableFuture.completedFuture(CommandResult.fromSuccess());
|
||||
} else {
|
||||
List<String> additionalFeatures = featureDependencies
|
||||
.stream()
|
||||
.map(featureDef -> featureDef.getFeature().getKey()).
|
||||
collect(Collectors.toList());
|
||||
FeatureSwitchModel model = (FeatureSwitchModel) ContextConverter.fromCommandContext(commandContext, FeatureSwitchModel.class);
|
||||
model.setFeatures(additionalFeatures);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(ENABLE_FEATURE_DEPENDENCIES_RESPONSE_TEMPLATE_KEY,
|
||||
model, commandContext.getGuild().getIdLong());
|
||||
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))
|
||||
.thenApply(message -> CommandResult.fromIgnored());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package dev.sheldan.abstracto.core.commands.config;
|
||||
package dev.sheldan.abstracto.core.commands.config.features;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.command.config.features.CoreFeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
||||
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
||||
import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.core.exception.FeatureNotFoundException;
|
||||
@@ -2,6 +2,7 @@ package dev.sheldan.abstracto.core.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.service.ExceptionService;
|
||||
import dev.sheldan.abstracto.core.config.FeatureConfig;
|
||||
import dev.sheldan.abstracto.core.config.PostTargetEnum;
|
||||
import dev.sheldan.abstracto.core.exception.ChannelNotInGuildException;
|
||||
import dev.sheldan.abstracto.core.interactive.*;
|
||||
import dev.sheldan.abstracto.core.models.AServerChannelUserId;
|
||||
@@ -14,9 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
@@ -62,7 +61,12 @@ public class FeatureSetupServiceBean implements FeatureSetupService {
|
||||
featureConfig.getFeature().getKey(), user.getUserId(), user.getChannelId(), user.getGuildId());
|
||||
Optional<TextChannel> textChannelInGuild = channelService.getTextChannelFromServerOptional(user.getGuildId(), user.getChannelId());
|
||||
if (textChannelInGuild.isPresent()) {
|
||||
List<String> requiredSystemConfigKeys = featureConfig.getRequiredSystemConfigKeys();
|
||||
Set<String> requiredSystemConfigKeys = new HashSet<>();
|
||||
Set<PostTargetEnum> requiredPostTargets = new HashSet<>();
|
||||
Set<SetupStep> customSetupSteps = new HashSet<>();
|
||||
|
||||
collectRequiredFeatureSteps(featureConfig, requiredSystemConfigKeys, requiredPostTargets, customSetupSteps, new HashSet<>());
|
||||
|
||||
List<SetupExecution> steps = new ArrayList<>();
|
||||
requiredSystemConfigKeys.forEach(s -> {
|
||||
log.debug("Feature requires system config key {}.", s);
|
||||
@@ -73,7 +77,7 @@ public class FeatureSetupServiceBean implements FeatureSetupService {
|
||||
.build();
|
||||
steps.add(execution);
|
||||
});
|
||||
featureConfig.getRequiredPostTargets().forEach(postTargetEnum -> {
|
||||
requiredPostTargets.forEach(postTargetEnum -> {
|
||||
log.debug("Feature requires post target {}.", postTargetEnum.getKey());
|
||||
SetupExecution execution = SetupExecution
|
||||
.builder()
|
||||
@@ -82,7 +86,7 @@ public class FeatureSetupServiceBean implements FeatureSetupService {
|
||||
.build();
|
||||
steps.add(execution);
|
||||
});
|
||||
featureConfig.getCustomSetupSteps().forEach(setupStep -> {
|
||||
customSetupSteps.forEach(setupStep -> {
|
||||
log.debug("Feature requires custom setup step {}.", setupStep.getClass().getName());
|
||||
SetupExecution execution = SetupExecution
|
||||
.builder()
|
||||
@@ -202,4 +206,19 @@ public class FeatureSetupServiceBean implements FeatureSetupService {
|
||||
aServerChannelUserId.getUserId(), aServerChannelUserId.getChannelId(), aServerChannelUserId.getGuildId(), featureConfig.getFeature().getKey());
|
||||
notifyUserWithTemplate(aServerChannelUserId, featureConfig, FEATURE_SETUP_CANCELLATION_NOTIFICATION_TEMPLATE);
|
||||
}
|
||||
|
||||
private void collectRequiredFeatureSteps(FeatureConfig featureConfig, Set<String> requiredSystemConfigKeys,
|
||||
Set<PostTargetEnum> requiredPostTargets, Set<SetupStep> customSetupSteps,
|
||||
Set<String> coveredFeatures) {
|
||||
if (coveredFeatures.contains(featureConfig.getFeature().getKey())) {
|
||||
return;
|
||||
}
|
||||
coveredFeatures.add(featureConfig.getFeature().getKey());
|
||||
requiredSystemConfigKeys.addAll(featureConfig.getRequiredSystemConfigKeys());
|
||||
requiredPostTargets.addAll(featureConfig.getRequiredPostTargets());
|
||||
customSetupSteps.addAll(featureConfig.getCustomSetupSteps());
|
||||
featureConfig.getRequiredFeatures()
|
||||
.forEach(requiredFeature -> collectRequiredFeatureSteps(requiredFeature, requiredSystemConfigKeys, requiredPostTargets, customSetupSteps, coveredFeatures));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,6 @@ import java.util.List;
|
||||
@Getter
|
||||
@Setter
|
||||
@SuperBuilder
|
||||
public class EnableModel extends UserInitiatedServerContext {
|
||||
public class FeatureSwitchModel extends UserInitiatedServerContext {
|
||||
private List<String> features;
|
||||
}
|
||||
Reference in New Issue
Block a user