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

@@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -11,17 +12,23 @@ import java.util.List;
public abstract class AbstractConditionableCommand implements ConditionalCommand {
@Autowired
private FeatureEnabledCondition featureEnabledCondition;
protected FeatureEnabledCondition featureEnabledCondition;
@Autowired
private CommandDisabledCondition commandDisabledCondition;
protected CommandDisabledCondition commandDisabledCondition;
@Autowired
protected ChannelService channelService;
@Autowired
protected CommandDisallowedCondition commandDisallowedCondition;
@Autowired
protected ImmuneUserCondition immuneUserCondition;
@Override
public List<CommandCondition> getConditions() {
return Arrays.asList(featureEnabledCondition, commandDisabledCondition);
return new ArrayList<>(Arrays.asList(featureEnabledCondition, commandDisabledCondition, commandDisallowedCondition));
}
}

View File

@@ -0,0 +1,56 @@
package dev.sheldan.abstracto.core.command.condition;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.models.InsufficientPermissionMessage;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.models.database.ACommandInAServer;
import dev.sheldan.abstracto.core.command.service.ChannelGroupCommandService;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.templating.service.TemplateService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.locks.Condition;
@Component
public class CommandDisallowedCondition implements CommandCondition {
@Autowired
private CommandInServerManagementService commandInServerManagementService;
@Autowired
private CommandManagementService commandService;
@Autowired
private RoleService roleService;
@Autowired
private TemplateService templateService;
@Override
public ConditionResult shouldExecute(CommandContext context, Command command) {
ACommand aCommand = commandService.findCommandByName(command.getConfiguration().getName());
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, context.getUserInitiatedContext().getServer());
if(!commandForServer.getRestricted()) {
return ConditionResult.builder().result(true).build();
}
for (ARole role : commandForServer.getAllowedRoles()) {
if (roleService.memberHasRole(context.getAuthor(), role)) {
return ConditionResult.builder().result(true).build();
}
}
InsufficientPermissionMessage insufficientPermissionMessage = InsufficientPermissionMessage
.builder()
.allowedRoles(roleService.getRolesFromGuild(commandForServer.getAllowedRoles()))
.build();
String message = templateService.renderTemplate("insufficient_role", insufficientPermissionMessage);
return ConditionResult.builder().result(false).reason(message).build();
}
}

View File

@@ -0,0 +1,60 @@
package dev.sheldan.abstracto.core.command.condition;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.models.UserImmuneMessage;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.models.database.ACommandInAServer;
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.templating.service.TemplateService;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
public class ImmuneUserCondition implements CommandCondition {
@Autowired
private CommandInServerManagementService commandInServerManagementService;
@Autowired
private CommandManagementService commandService;
@Autowired
private RoleService roleService;
@Autowired
private TemplateService templateService;
@Override
public ConditionResult shouldExecute(CommandContext context, Command command) {
ACommand aCommand = commandService.findCommandByName(command.getConfiguration().getName());
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, context.getUserInitiatedContext().getServer());
Optional<Member> any = context.getParameters().getParameters().stream().filter(o -> o instanceof Member).map(this::toMember).findAny();
if(any.isPresent()) {
Member member = any.get();
for (ARole role : commandForServer.getImmuneRoles()) {
if (roleService.memberHasRole(member, role)) {
UserImmuneMessage userImmuneMessage = UserImmuneMessage
.builder()
.role(roleService.getRoleFromGuild(role))
.build();
String message = templateService.renderTemplate("immune_role", userImmuneMessage);
return ConditionResult.builder().result(false).reason(message).build();
}
}
}
return ConditionResult.builder().result(true).build();
}
private Member toMember(Object o) {
return (Member) o;
}
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.command.models;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Role;
import java.util.List;
@Setter
@Getter
@Builder
public class InsufficientPermissionMessage {
private List<Role> allowedRoles;
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.core.command.models;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.Role;
@Getter
@Setter
@Builder
public class UserImmuneMessage {
private Role role;
}

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.core.command.models.database;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AFeature;
import lombok.*;
import javax.persistence.*;
@@ -26,10 +26,10 @@ public class ACommand {
@JoinColumn(name = "module_id", nullable = false)
private AModule module;
@ManyToMany(fetch = FetchType.LAZY)
@Getter
@JoinColumn(name = "allowed_role_id")
private List<ARole> allowedRoles;
@Setter
@ManyToOne
@JoinColumn(name = "feature_id", nullable = false)
private AFeature feature;
}

View File

@@ -0,0 +1,48 @@
package dev.sheldan.abstracto.core.command.models.database;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
import lombok.*;
import javax.persistence.*;
import java.util.List;
@Entity
@Getter
@Builder
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class ACommandInAServer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long commandInServerId;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "commandReference", nullable = false)
private ACommand commandReference;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "serverReference", nullable = false)
private AServer serverReference;
@ManyToMany(fetch = FetchType.LAZY)
@Getter
@JoinColumn(name = "allowed_role_id")
private List<ARole> allowedRoles;
@ManyToMany(fetch = FetchType.LAZY)
@Getter
@JoinColumn(name = "immune_role_id")
private List<ARole> immuneRoles;
@Getter
@Setter
@Column
private Boolean restricted;
}

View File

@@ -1,8 +1,17 @@
package dev.sheldan.abstracto.core.command.service;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer;
public interface CommandService {
ACommand createCommand(String name, String moduleName);
ACommand createCommand(String name, String moduleName, FeatureEnum featureEnum);
Boolean doesCommandExist(String name);
void allowCommandForRole(ACommand aCommand, ARole role);
void makeRoleImmuneForCommand(ACommand aCommand, ARole role);
void makeRoleAffectedByCommand(ACommand aCommand, ARole role);
void restrictCommand(ACommand aCommand, AServer server);
void unRestrictCommand(ACommand aCommand, AServer server);
void disAllowCommandForRole(ACommand aCommand, ARole role);
}

View File

@@ -0,0 +1,11 @@
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.models.database.AServer;
public interface CommandInServerManagementService {
ACommandInAServer crateCommandInServer(ACommand command, AServer server);
boolean doesCommandExistInServer(ACommand command, AServer server);
ACommandInAServer getCommandForServer(ACommand command, AServer server);
}

View File

@@ -2,10 +2,11 @@ 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.models.database.AFeature;
public interface CommandManagementService {
ACommand createCommand(String name, String moduleName);
ACommand createCommand(String name, AModule moduleName);
ACommand createCommand(String name, String moduleName, String featureName);
ACommand createCommand(String name, AModule moduleName, AFeature feature);
ACommand findCommandByName(String name);
Boolean doesCommandExist(String name);
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.core.command.service.management;
import dev.sheldan.abstracto.core.models.database.AFeature;
public interface FeatureManagementService {
AFeature createFeature(String key);
boolean featureExists(String key);
AFeature getFeature(String key);
}

View File

@@ -0,0 +1,33 @@
package dev.sheldan.abstracto.core.models.database;
import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.models.SnowFlake;
import lombok.*;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name="feature")
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AFeature implements SnowFlake {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Getter
@Column(name = "id")
public Long id;
@Getter
@Setter
private String key;
@Getter
@Setter
@OneToMany
@JoinColumn(name = "feature_id")
private List<ACommand> commands;
}

View File

@@ -10,7 +10,7 @@ import javax.persistence.*;
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AFeatureFlag implements SnowFlake {
public class AFeatureFlag {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -26,7 +26,9 @@ public class AFeatureFlag implements SnowFlake {
@Getter
@Setter
private String key;
@OneToOne
@JoinColumn(name = "feature_id", nullable = false)
private AFeature feature;
@Getter
@Setter

View File

@@ -5,12 +5,15 @@ import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Role;
import java.util.List;
public interface RoleService {
void addRoleToUser(AUserInAServer aUserInAServer, ARole role);
void removeRoleFromUser(AUserInAServer aUserInAServer, ARole role);
void markDeleted(Role role);
void markDeleted(Long id);
Role getRoleFromGuild(ARole role);
List<Role> getRolesFromGuild(List<ARole> roles);
boolean memberHasRole(Member member, Role role);
boolean memberHasRole(Member member, ARole role);
boolean isRoleInServer(ARole role);

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.service.management;
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;
@@ -8,10 +9,10 @@ import java.util.List;
import java.util.Optional;
public interface FeatureFlagManagementService {
void createFeatureFlag(FeatureEnum key, Long serverId, Boolean newValue);
void createFeatureFlag(FeatureEnum key, AServer server, Boolean newValue);
void createFeatureFlag(AFeature feature, Long serverId, Boolean newValue);
void createFeatureFlag(AFeature feature, AServer server, Boolean newValue);
boolean getFeatureFlagValue(FeatureEnum key, Long serverId);
void updateFeatureFlag(FeatureEnum key, Long serverId, Boolean newValue);
Optional<AFeatureFlag> getFeatureFlag(FeatureEnum key, Long serverId);
Optional<AFeatureFlag> getFeatureFlag(AFeature key, Long serverId);
List<AFeatureFlag> getFeatureFlagsOfServer(AServer server);
}