mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-03-24 21:53:22 +00:00
moved commands into the core, because its a core functionality
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public abstract class AbstractFeatureFlaggedCommand implements ConditionalCommand {
|
||||
|
||||
@Autowired
|
||||
private FeatureEnabledCondition featureEnabledCondition;
|
||||
|
||||
@Override
|
||||
public List<CommandCondition> getConditions() {
|
||||
return Arrays.asList(featureEnabledCondition);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.listener.FeatureAware;
|
||||
|
||||
public interface Command extends FeatureAware {
|
||||
|
||||
CommandResult execute(CommandContext commandContext);
|
||||
CommandConfiguration getConfiguration();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
|
||||
public interface CommandCondition {
|
||||
boolean shouldExecute(CommandContext commandContext, Command command);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter @Builder
|
||||
public class CommandHierarchy {
|
||||
private List<PackedModule> rootModules;
|
||||
|
||||
public PackedModule getModuleWithName(String name){
|
||||
for (PackedModule module: rootModules) {
|
||||
PackedModule found = getModuleWithName(name, module);
|
||||
if(found != null){
|
||||
return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private PackedModule getModuleWithName(String name, PackedModule module){
|
||||
if(module.getModuleInterface().getInfo().getName().equals(name)){
|
||||
return module;
|
||||
} else {
|
||||
for (PackedModule subModule: module.getSubModules()) {
|
||||
PackedModule possibleModule = getModuleWithName(name, subModule);
|
||||
if(possibleModule != null){
|
||||
return possibleModule;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Command getCommandWithName(String name) {
|
||||
for (PackedModule module: rootModules) {
|
||||
Command command = getCommandFromModule(name, module);
|
||||
if(command != null){
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Command getCommandFromModule(String name, PackedModule module){
|
||||
Command foundCommand = module.getCommands().stream().filter(command -> command.getConfiguration().getName().equals(name)).findAny().orElse(null);
|
||||
if(foundCommand == null){
|
||||
for (PackedModule subModule: module.getSubModules()) {
|
||||
Command command = getCommandFromModule(name, subModule);
|
||||
if(command != null){
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
return foundCommand;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ConditionalCommand extends Command {
|
||||
List<CommandCondition> getConditions();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.service.management.FeatureFlagManagementService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class FeatureEnabledCondition implements CommandCondition {
|
||||
|
||||
@Autowired
|
||||
private FeatureFlagManagementService featureFlagManagementService;
|
||||
|
||||
@Override
|
||||
public boolean shouldExecute(CommandContext context, Command command) {
|
||||
String featureName = command.getFeature();
|
||||
if(featureName != null) {
|
||||
return featureFlagManagementService.getFeatureFlagValue(featureName, context.getGuild().getIdLong());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter @Builder
|
||||
public class HelpInfo {
|
||||
private String usage;
|
||||
private String longHelp;
|
||||
private boolean templated;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
|
||||
import dev.sheldan.abstracto.core.command.module.ModuleInfo;
|
||||
|
||||
public interface ModuleInterface {
|
||||
ModuleInfo getInfo();
|
||||
String getParentModule();
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class PackedModule {
|
||||
private ModuleInterface moduleInterface;
|
||||
private PackedModule parentModule;
|
||||
private List<PackedModule> subModules;
|
||||
private List<Command> commands;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package dev.sheldan.abstracto.core.command;
|
||||
|
||||
public interface Templatable {
|
||||
String getTemplateName();
|
||||
Object getTemplateModel();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package dev.sheldan.abstracto.core.command.execution;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.HelpInfo;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter @Builder
|
||||
public class CommandConfiguration {
|
||||
|
||||
private String name;
|
||||
private String module;
|
||||
private String description;
|
||||
private List<Parameter> parameters;
|
||||
private List<String> aliases;
|
||||
private boolean causesReaction;
|
||||
private boolean templated;
|
||||
private HelpInfo help;
|
||||
|
||||
public int getNecessaryParameterCount(){
|
||||
return (int) parameters.stream().filter(parameter -> !parameter.isOptional()).count();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package dev.sheldan.abstracto.core.command.execution;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.UserInitiatedServerContext;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Guild;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public class CommandContext {
|
||||
private TextChannel channel;
|
||||
private Guild guild;
|
||||
private Member author;
|
||||
private Message message;
|
||||
private UserInitiatedServerContext userInitiatedContext;
|
||||
private Parameters parameters;
|
||||
private JDA jda;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package dev.sheldan.abstracto.core.command.execution;
|
||||
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter @Setter @Builder
|
||||
public class CommandResult {
|
||||
private ResultState result;
|
||||
private String message;
|
||||
private Throwable throwable;
|
||||
|
||||
public static CommandResult fromSuccess() {
|
||||
return CommandResult.builder().result(ResultState.SUCCESSFUL).build();
|
||||
}
|
||||
|
||||
public static CommandResult fromError(String message){
|
||||
return CommandResult.builder().result(ResultState.ERROR).message(message).build();
|
||||
}
|
||||
|
||||
public static CommandResult fromError(String message, Throwable throwable) {
|
||||
return CommandResult.builder().result(ResultState.ERROR).message(message).throwable(throwable).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.sheldan.abstracto.core.command.execution;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.UserInitiatedServerContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@Slf4j
|
||||
public class ContextConverter {
|
||||
|
||||
public static <T extends UserInitiatedServerContext> UserInitiatedServerContext fromCommandContext(CommandContext commandContext, Class<T> clazz) {
|
||||
Method m = null;
|
||||
try {
|
||||
m = clazz.getMethod("builder");
|
||||
UserInitiatedServerContext.UserInitiatedServerContextBuilder<?, ?> builder = (UserInitiatedServerContext.UserInitiatedServerContextBuilder) m.invoke(null, null);
|
||||
return builder
|
||||
.member(commandContext.getAuthor())
|
||||
.guild(commandContext.getGuild())
|
||||
.messageChannel(commandContext.getChannel())
|
||||
.channel(commandContext.getUserInitiatedContext().getChannel())
|
||||
.server(commandContext.getUserInitiatedContext().getServer())
|
||||
.aUserInAServer(commandContext.getUserInitiatedContext().getAUserInAServer())
|
||||
.user(commandContext.getUserInitiatedContext().getUser())
|
||||
.build();
|
||||
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
||||
log.error("Failed to execute builder method", e);
|
||||
}
|
||||
throw new RuntimeException("Failed to create model from context");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package dev.sheldan.abstracto.core.command.execution;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter @Setter @Builder
|
||||
public class Parameter {
|
||||
private String name;
|
||||
private Class type;
|
||||
private String description;
|
||||
private boolean optional;
|
||||
private boolean remainder;
|
||||
private Integer maxLength;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.abstracto.core.command.execution;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Builder
|
||||
public class Parameters {
|
||||
@Getter
|
||||
private List<Object> parameters;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package dev.sheldan.abstracto.core.command.execution;
|
||||
|
||||
public enum ResultState {
|
||||
ERROR, SUCCESSFUL, IGNORED
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.sheldan.abstracto.core.command.meta;
|
||||
|
||||
|
||||
import dev.sheldan.abstracto.core.command.Command;
|
||||
import dev.sheldan.abstracto.core.command.ModuleInterface;
|
||||
import dev.sheldan.abstracto.core.command.module.ModuleInfo;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CommandRegistry {
|
||||
Command findCommandByParameters(String name, UnParsedCommandParameter context);
|
||||
Command findCommand(String message);
|
||||
List<Command> getAllCommands();
|
||||
List<Command> getAllCommandsFromModule(ModuleInterface module);
|
||||
boolean isCommand(Message message);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package dev.sheldan.abstracto.core.command.meta;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Getter
|
||||
public class UnParsedCommandParameter {
|
||||
|
||||
private static Pattern SPLIT_REGEX = Pattern.compile("\"([^\"]*)\"|(\\S+)");
|
||||
|
||||
public UnParsedCommandParameter(String parameters) {
|
||||
this.parameters = new ArrayList<>();
|
||||
Matcher m = SPLIT_REGEX.matcher(parameters);
|
||||
boolean skippedCommand = false;
|
||||
while (m.find()) {
|
||||
if(!skippedCommand) {
|
||||
skippedCommand = true;
|
||||
continue;
|
||||
}
|
||||
if (m.group(1) != null) {
|
||||
String group = m.group(1);
|
||||
if(!group.equals("")) {
|
||||
this.parameters.add(group);
|
||||
}
|
||||
} else {
|
||||
String group = m.group(2);
|
||||
if(!group.equals("")) {
|
||||
this.parameters.add(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private List<String> parameters;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package dev.sheldan.abstracto.core.command.models;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "channel_group_command")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class AChannelGroupCommand {
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "command_id", nullable = false)
|
||||
@Getter
|
||||
@Setter
|
||||
@Column
|
||||
private ACommand command;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "group_id", nullable = false)
|
||||
@Getter
|
||||
@Setter
|
||||
@Column
|
||||
private AChannelGroup group;
|
||||
|
||||
private Boolean enabled;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package dev.sheldan.abstracto.core.command.models;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "command")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class ACommand {
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@Getter
|
||||
@Setter
|
||||
@JoinColumn(name = "module_id")
|
||||
private AModule module;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package dev.sheldan.abstracto.core.command.models;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Entity
|
||||
@Table(name = "module")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class AModule {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@OneToMany(
|
||||
fetch = FetchType.LAZY,
|
||||
cascade = CascadeType.ALL,
|
||||
orphanRemoval = true)
|
||||
@Builder.Default
|
||||
@JoinColumn(name = "module_id")
|
||||
private List<ACommand> commands = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package dev.sheldan.abstracto.core.command.module;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.ModuleInterface;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AbstracatoModuleInterface implements ModuleInterface {
|
||||
@Override
|
||||
public ModuleInfo getInfo() {
|
||||
return ModuleInfo.builder().name("default").description("Default module provided by abstracto").build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParentModule() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package dev.sheldan.abstracto.core.command.module;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter @Builder
|
||||
public class ModuleInfo {
|
||||
|
||||
private String name;
|
||||
private String description;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package dev.sheldan.abstracto.core.command.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.models.ACommand;
|
||||
|
||||
public interface CommandService {
|
||||
ACommand createCommand(String name, String moduleName);
|
||||
Boolean doesCommandExist(String name);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package dev.sheldan.abstracto.core.command.service;
|
||||
|
||||
|
||||
import dev.sheldan.abstracto.core.command.CommandHierarchy;
|
||||
import dev.sheldan.abstracto.core.command.ModuleInterface;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ModuleRegistry {
|
||||
CommandHierarchy getDetailedModules();
|
||||
List<ModuleInterface> getModuleInterfaces();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package dev.sheldan.abstracto.core.command.service;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.Command;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
|
||||
public interface PostCommandExecution {
|
||||
void execute(CommandContext commandContext, CommandResult commandResult, Command command);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package dev.sheldan.abstracto.core.command.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.models.ACommand;
|
||||
import dev.sheldan.abstracto.core.command.models.AModule;
|
||||
|
||||
public interface CommandManagementService {
|
||||
ACommand createCommand(String name, String moduleName);
|
||||
ACommand createCommand(String name, AModule moduleName);
|
||||
ACommand findCommandByName(String name);
|
||||
Boolean doesCommandExist(String name);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package dev.sheldan.abstracto.core.command.service.management;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.models.AModule;
|
||||
|
||||
public interface ModuleManagementService {
|
||||
AModule createModule(String name);
|
||||
AModule getOrCreate(String name);
|
||||
AModule findModuleByName(String name);
|
||||
Boolean doesModuleExist(String name);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package dev.sheldan.abstracto.core.models.database;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.models.ACommand;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "channel_group_command")
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class AChannelGroupCommand {
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "command_id", nullable = false)
|
||||
@Getter
|
||||
@Setter
|
||||
@Column
|
||||
private ACommand command;
|
||||
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "group_id", nullable = false)
|
||||
@Getter
|
||||
@Setter
|
||||
@Column
|
||||
private AChannelGroup group;
|
||||
|
||||
private Boolean enabled;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user