[AB-128] adding command cooldowns on server/channel group and member level

fixing channel group names being made lower case before storing
changing channel group deleted to be sync instead
refactoring exceptions and adding exception message to a few
fixing channel group incorrect type using the wrong template
showing more information in list channel groups command
allowing commands to be in any channel group
adding concept of channel group types not allowing channels/commands to be in multiple of the same type
adding structure to retrieve information about channel groups
adding ability to disable channel groups
changing loading of member parameter handler to not use cache
This commit is contained in:
Sheldan
2021-04-19 00:25:42 +02:00
parent d540ad80a8
commit 49a9598062
127 changed files with 2325 additions and 189 deletions

View File

@@ -3,4 +3,7 @@ package dev.sheldan.abstracto.modmail.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
public class ModMailThreadChannelNotFound extends AbstractoRunTimeException {
public ModMailThreadChannelNotFound() {
super("Modmail thread channel not found.");
}
}

View File

@@ -1,7 +1,7 @@
package dev.sheldan.abstracto.repostdetection.listener;
import dev.sheldan.abstracto.core.listener.DefaultListenerResult;
import dev.sheldan.abstracto.core.listener.sync.entity.AsyncChannelGroupDeletedListener;
import dev.sheldan.abstracto.core.listener.sync.entity.ChannelGroupDeletedListener;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.listener.ChannelGroupDeletedListenerModel;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
@@ -11,7 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class RepostCheckAsyncChannelGroupDeletedListener implements AsyncChannelGroupDeletedListener {
public class RepostCheckChannelGroupDeletedListener implements ChannelGroupDeletedListener {
@Autowired
private RepostCheckChannelGroupManagement checkChannelGroupManagement;

View File

@@ -16,10 +16,10 @@ import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class RepostCheckAsyncChannelGroupDeletedListenerTest {
public class RepostCheckChannelGroupDeletedListenerTest {
@InjectMocks
private RepostCheckAsyncChannelGroupDeletedListener testUnit;
private RepostCheckChannelGroupDeletedListener testUnit;
@Mock
private RepostCheckChannelGroupManagement checkChannelGroupManagement;

View File

@@ -14,6 +14,7 @@ public class TrackedEmoteNotFoundException extends AbstractoRunTimeException imp
}
public TrackedEmoteNotFoundException() {
super("Tracked emote not found.");
}
@Override

View File

@@ -4,6 +4,10 @@ import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class NoUrbanDefinitionFoundException extends AbstractoRunTimeException implements Templatable {
public NoUrbanDefinitionFoundException() {
super("No urban definition found.");
}
@Override
public String getTemplateName() {
return "no_urban_definition_found_exception";

View File

@@ -9,6 +9,7 @@ public class YoutubeAPIException extends AbstractoRunTimeException implements Te
private final YoutubeAPIExceptionModel model;
public YoutubeAPIException(Throwable throwable) {
super("Youtube api exception.");
this.model = YoutubeAPIExceptionModel
.builder()
.exception(throwable)

View File

@@ -5,6 +5,10 @@ import dev.sheldan.abstracto.core.templating.Templatable;
public class YoutubeVideoNotFoundException extends AbstractoRunTimeException implements Templatable {
public YoutubeVideoNotFoundException() {
super("No youtube video found.");
}
@Override
public String getTemplateName() {
return "webservices_youtube_video_not_found_exception";

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.command.execution.UnparsedCommandParameterPiec
import dev.sheldan.abstracto.core.command.handler.provided.MemberParameterHandler;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.utils.concurrent.Task;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Component;
@@ -38,14 +39,19 @@ public class MemberParameterHandlerImpl implements MemberParameterHandler {
long userId = Long.parseLong(inputString);
return context.getGuild().retrieveMemberById(userId).submit().thenApply(member -> member);
} else {
List<Member> possibleMembers = context.getGuild().getMembersByName(inputString, true);
if(possibleMembers.isEmpty()) {
throw new AbstractoTemplatedException("No member found with name.", "no_member_found_by_name_exception");
}
if(possibleMembers.size() > 1) {
throw new AbstractoTemplatedException("Multiple members found with name.", "multiple_members_found_by_name_exception");
}
return CompletableFuture.completedFuture(possibleMembers.get(0));
Task<List<Member>> listTask = context.getGuild().retrieveMembersByPrefix(inputString, 1);
CompletableFuture<Object> memberFuture = new CompletableFuture<>();
listTask.onSuccess(members -> {
if(members.isEmpty()) {
memberFuture.completeExceptionally(new AbstractoTemplatedException("No member found with name.", "no_member_found_by_name_exception"));
} else if(members.size() > 1) {
memberFuture.completeExceptionally(new AbstractoTemplatedException("Multiple members found with name.", "multiple_members_found_by_name_exception"));
} else {
memberFuture.complete(members.get(0));
}
});
listTask.onError(memberFuture::completeExceptionally);
return memberFuture;
}
}

View File

@@ -0,0 +1,27 @@
package dev.sheldan.abstracto.core.command.post;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ResultState;
import dev.sheldan.abstracto.core.command.service.CommandCoolDownService;
import dev.sheldan.abstracto.core.command.service.PostCommandExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
public class CoolDownPostExecution implements PostCommandExecution {
@Autowired
private CommandCoolDownService commandCoolDownService;
@Override
@Transactional
public void execute(CommandContext commandContext, CommandResult commandResult, Command command) {
ResultState result = commandResult.getResult();
if(result.equals(ResultState.SUCCESSFUL) || result.equals(ResultState.IGNORED)) {
commandCoolDownService.updateCoolDowns(command, commandContext);
}
}
}

View File

@@ -11,6 +11,8 @@ import java.util.Optional;
public interface ChannelGroupCommandRepository extends JpaRepository<AChannelGroupCommand, Long> {
Optional<AChannelGroupCommand> findByCommandAndGroup(ACommand command, AChannelGroup group);
List<AChannelGroupCommand> findByCommandAndGroupIn(ACommand command, List<AChannelGroup> groups);
List<AChannelGroupCommand> findByCommand(ACommand command);
List<AChannelGroupCommand> findByCommandAndGroup_ChannelGroupType_GroupTypeKey(ACommand command, String groupType);
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.core.command.repository;
import dev.sheldan.abstracto.core.command.model.database.CommandDisabledChannelGroup;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CommandDisabledChannelGroupRepository extends JpaRepository<CommandDisabledChannelGroup, Long> {
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.core.command.repository;
import dev.sheldan.abstracto.core.command.model.database.CoolDownChannelGroup;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface CoolDownChannelGroupRepository extends JpaRepository<CoolDownChannelGroup, Long> {
}

View File

@@ -12,6 +12,8 @@ import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
import static dev.sheldan.abstracto.core.command.CommandConstants.COMMAND_CHANNEL_GROUP_KEY;
@Component
@Slf4j
public class ChannelGroupCommandServiceBean implements ChannelGroupCommandService {
@@ -24,12 +26,17 @@ public class ChannelGroupCommandServiceBean implements ChannelGroupCommandServic
@Override
public Boolean isCommandEnabled(ACommand command, AChannel channel) {
List<AChannelGroupCommand> allChannelGroupsOfCommand = channelGroupCommandService.getAllGroupCommandsForCommand(command);
List<AChannelGroupCommand> allChannelGroupsOfCommand =
channelGroupCommandService.getAllGroupCommandsForCommandWithType(command, COMMAND_CHANNEL_GROUP_KEY);
for (AChannelGroupCommand aChannelGroupCommand : allChannelGroupsOfCommand) {
if(!aChannelGroupCommand.getGroup().getEnabled()) {
continue;
}
Optional<AChannel> channelInGroup = aChannelGroupCommand.getGroup()
.getChannels().stream().filter(innerChannel -> innerChannel.getId().equals(channel.getId())).findAny();
if (channelInGroup.isPresent() && !aChannelGroupCommand.getEnabled()) {
log.debug("Command {} is disabled because the channel is part of group {} in server.", command.getName(), aChannelGroupCommand.getGroup().getId());
log.debug("Command {} is disabled because the channel is part of group {} in server.", command.getName(),
aChannelGroupCommand.getGroup().getId());
return false;
}
}

View File

@@ -0,0 +1,28 @@
package dev.sheldan.abstracto.core.command.service;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
@Component
@Getter
public class CommandCoolDownRuntimeStorage {
// maps server ID to command name to time at which the command can be executed again
private Map<Long, CommandReUseMap> serverCoolDowns = new HashMap<>();
// maps server ID to channel group ID to command name to time at which the command can be executed again
private Map<Long, Map<Long, CommandReUseMap>> channelGroupCoolDowns = new HashMap<>();
// maps server ID to member ID to command name to time at which the command can be executed again
private Map<Long, Map<Long, CommandReUseMap>> memberCoolDowns = new HashMap<>();
}
@Getter
@Setter
@Builder
class CommandReUseMap {
private Map<String, Instant> reUseTimes;
}

View File

@@ -0,0 +1,401 @@
package dev.sheldan.abstracto.core.command.service;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CoolDownCheckResult;
import dev.sheldan.abstracto.core.command.model.database.ACommand;
import dev.sheldan.abstracto.core.command.model.database.ACommandInAServer;
import dev.sheldan.abstracto.core.command.model.database.CoolDownChannelGroup;
import dev.sheldan.abstracto.core.command.service.management.ChannelGroupCommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.models.AServerChannelUserId;
import dev.sheldan.abstracto.core.models.ServerIdChannelId;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import dev.sheldan.abstracto.core.service.ChannelGroupService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.CoolDownChannelGroupManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@Component
@Slf4j
public class CommandCoolDownServiceBean implements CommandCoolDownService {
@Autowired
private CommandCoolDownRuntimeStorage storage;
private static final Lock runTimeLock = new ReentrantLock();
@Autowired
private ChannelGroupService channelGroupService;
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private CommandInServerManagementService commandInServerManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private ChannelGroupCommandManagementService channelGroupCommandService;
@Autowired
private CoolDownChannelGroupManagementService coolDownChannelGroupManagementService;
public static final String COOL_DOWN_CHANNEL_GROUP_TYPE = "commandCoolDown";
@Override
public void takeLock() {
runTimeLock.lock();
}
@Override
public void releaseLock() {
runTimeLock.unlock();
}
@Override
public CoolDownCheckResult allowedToExecuteCommand(Command command, CommandContext context) {
Long serverId = context.getGuild().getIdLong();
Instant now = Instant.now();
String commandName = command.getConfiguration().getName();
Duration serverCooldown = null;
Duration channelCooldown = null;
Duration memberCooldown = null;
if(storage.getServerCoolDowns().containsKey(serverId)) {
CommandReUseMap serverMap = storage.getServerCoolDowns().get(serverId);
Duration durationToExecuteIn = getDurationToExecuteIn(now, commandName, serverMap);
if (durationIndicatesCoolDown(durationToExecuteIn)) {
serverCooldown = durationToExecuteIn;
}
}
if(storage.getChannelGroupCoolDowns().containsKey(serverId)) {
Map<Long, CommandReUseMap> serverMap = storage.getChannelGroupCoolDowns().get(serverId);
if(!serverMap.keySet().isEmpty()) {
Long channelId = context.getChannel().getIdLong();
AChannel channel = channelManagementService.loadChannel(channelId);
List<AChannelGroup> channelGroups =
channelGroupService.getChannelGroupsOfChannelWithType(channel, COOL_DOWN_CHANNEL_GROUP_TYPE);
for (AChannelGroup channelGroup : channelGroups) {
if(serverMap.containsKey(channelGroup.getId())) {
CommandReUseMap channelGroupMap = serverMap.get(channelGroup.getId());
Duration durationToExecuteIn = getDurationToExecuteIn(now, commandName, channelGroupMap);
if (durationIndicatesCoolDown(durationToExecuteIn)) {
channelCooldown = durationToExecuteIn;
}
}
}
}
}
if(storage.getMemberCoolDowns().containsKey(serverId)) {
Map<Long, CommandReUseMap> serverMap = storage.getMemberCoolDowns().get(serverId);
if(!serverMap.keySet().isEmpty()) {
Long memberId = context.getAuthor().getIdLong();
if(serverMap.containsKey(memberId)) {
CommandReUseMap commandReUseMap = serverMap.get(memberId);
Duration durationToExecuteIn = getDurationToExecuteIn(now, commandName, commandReUseMap);
if (durationIndicatesCoolDown(durationToExecuteIn)) {
memberCooldown = durationToExecuteIn;
}
}
}
}
if(serverCooldown != null || channelCooldown != null || memberCooldown != null) {
Long serverSeconds = serverCooldown != null ? serverCooldown.getSeconds() : 0L;
Long channelSeconds = channelCooldown != null ? channelCooldown.getSeconds() : 0L;
Long memberSeconds = memberCooldown != null ? memberCooldown.getSeconds() : 0L;
if(serverSeconds > channelSeconds && serverSeconds > memberSeconds) {
return CoolDownCheckResult.getServerCoolDown(serverCooldown);
}
if(channelSeconds > serverSeconds && channelSeconds > memberSeconds) {
return CoolDownCheckResult.getChannelGroupCoolDown(channelCooldown);
}
return CoolDownCheckResult.getMemberCoolDown(memberCooldown);
}
return CoolDownCheckResult.noCoolDown();
}
private boolean durationIndicatesCoolDown(Duration duration) {
return !duration.equals(Duration.ZERO) && !duration.isNegative();
}
@Override
public Duration getServerCoolDownForCommand(Command command, Long serverId) {
CommandConfiguration commandConfiguration = command.getConfiguration();
ACommand aCommand = commandManagementService.findCommandByName(commandConfiguration.getName());
return getServerCoolDownForCommand(aCommand, command, serverId);
}
@Override
public Duration getServerCoolDownForCommand(ACommand aCommand, Command command, Long serverId) {
CommandConfiguration commandConfiguration = command.getConfiguration();
ACommandInAServer commandInServer = commandInServerManagementService.getCommandForServer(aCommand, serverId);
if(commandInServer.getCoolDown() != null) {
return Duration.ofSeconds(commandInServer.getCoolDown());
}
if(commandConfiguration.getCoolDownConfig() != null) {
return commandConfiguration.getCoolDownConfig().getServerCoolDown();
}
return Duration.ZERO;
}
@Override
public Duration getChannelGroupCoolDownForCommand(Command command, ServerIdChannelId serverIdChannelId) {
CommandConfiguration commandConfiguration = command.getConfiguration();
ACommand aCommand = commandManagementService.findCommandByName(commandConfiguration.getName());
return getChannelGroupCoolDownForCommand(aCommand, command, serverIdChannelId);
}
@Override
public Duration getChannelGroupCoolDownForCommand(ACommand aCommand, Command command, ServerIdChannelId serverIdChannelId) {
CommandConfiguration commandConfiguration = command.getConfiguration();
AChannel channel = channelManagementService.loadChannel(serverIdChannelId.getChannelId());
List<AChannelGroup> channelGroups = channelGroupService.getChannelGroupsOfChannelWithType(channel, COOL_DOWN_CHANNEL_GROUP_TYPE);
List<AChannelGroupCommand> allChannelGroupsOfCommand =
channelGroupCommandService.getAllGroupCommandsForCommandInGroups(aCommand, channelGroups);
if(!allChannelGroupsOfCommand.isEmpty()) {
Long durationInSeconds = 0L;
if(allChannelGroupsOfCommand.size() > 1) {
log.info("Found multiple channel groups of type commandCoolDown for command {} in server {}. ",
command.getConfiguration().getName(), serverIdChannelId.getServerId());
}
for (AChannelGroupCommand channelGroupCommand : allChannelGroupsOfCommand) {
CoolDownChannelGroup channelGroup = coolDownChannelGroupManagementService.findByChannelGroupId(channelGroupCommand.getGroup().getId());
if (channelGroup.getChannelCoolDown() != null) {
durationInSeconds = Math.max(durationInSeconds, channelGroup.getChannelCoolDown());
}
}
return Duration.ofSeconds(durationInSeconds);
}
if(commandConfiguration.getCoolDownConfig() != null) {
return commandConfiguration.getCoolDownConfig().getChannelCoolDown();
}
return Duration.ZERO;
}
@Override
public Duration getMemberCoolDownForCommand(Command command, ServerIdChannelId serverIdChannelId) {
CommandConfiguration commandConfiguration = command.getConfiguration();
ACommand aCommand = commandManagementService.findCommandByName(commandConfiguration.getName());
return getMemberCoolDownForCommand(aCommand, command, serverIdChannelId);
}
@Override
public Duration getMemberCoolDownForCommand(ACommand aCommand, Command command, ServerIdChannelId serverIdChannelId) {
CommandConfiguration commandConfiguration = command.getConfiguration();
AChannel channel = channelManagementService.loadChannel(serverIdChannelId.getChannelId());
List<AChannelGroup> channelGroups = channelGroupService.getChannelGroupsOfChannelWithType(channel, COOL_DOWN_CHANNEL_GROUP_TYPE);
List<AChannelGroupCommand> allChannelGroupsOfCommand =
channelGroupCommandService.getAllGroupCommandsForCommandInGroups(aCommand, channelGroups);
if(!allChannelGroupsOfCommand.isEmpty()) {
Long durationInSeconds = 0L;
if(allChannelGroupsOfCommand.size() > 1) {
log.info("Found multiple channel groups of type commandCoolDown for command {} in server {}. ",
command.getConfiguration().getName(), serverIdChannelId.getServerId());
}
for (AChannelGroupCommand channelGroupCommand : allChannelGroupsOfCommand) {
CoolDownChannelGroup channelGroup = coolDownChannelGroupManagementService.findByChannelGroupId(channelGroupCommand.getGroup().getId());
if (channelGroup.getMemberCoolDown() != null) {
durationInSeconds = Math.max(durationInSeconds, channelGroup.getMemberCoolDown());
}
}
return Duration.ofSeconds(durationInSeconds);
}
if(commandConfiguration.getCoolDownConfig() != null) {
return commandConfiguration.getCoolDownConfig().getMemberCoolDown();
}
return Duration.ZERO;
}
@Override
public void addServerCoolDown(Command command, Long serverId) {
addServerCoolDown(command, serverId, true);
}
@Override
public void addServerCoolDown(Command command, Long serverId, boolean takeLock) {
if(takeLock) {
takeLock();
}
try {
Duration coolDown = getServerCoolDownForCommand(command, serverId);
Instant newExecutionPoint = Instant.now().plus(coolDown);
String commandName = command.getConfiguration().getName();
Map<Long, CommandReUseMap> serverCoolDowns = storage.getServerCoolDowns();
createReUseMapIfNotExists(newExecutionPoint, commandName, serverCoolDowns, serverId);
} finally {
if(takeLock) {
releaseLock();
}
}
}
@Override
public void addChannelCoolDown(Command command, ServerIdChannelId serverIdChannelId) {
addChannelCoolDown(command, serverIdChannelId, true);
}
@Override
public void addChannelCoolDown(Command command, ServerIdChannelId serverIdChannelId, boolean takeLock) {
if(takeLock) {
takeLock();
}
try {
Duration coolDown = getChannelGroupCoolDownForCommand(command, serverIdChannelId);
Instant newExecutionPoint = Instant.now().plus(coolDown);
String commandName = command.getConfiguration().getName();
Long serverId = serverIdChannelId.getServerId();
Map<Long, Map<Long, CommandReUseMap>> serverChannelGroupCoolDowns = storage.getChannelGroupCoolDowns();
Map<Long, CommandReUseMap> channelGroupCoolDowns;
if(serverChannelGroupCoolDowns.containsKey(serverId)) {
channelGroupCoolDowns = serverChannelGroupCoolDowns.get(serverId);
} else {
channelGroupCoolDowns = new HashMap<>();
serverChannelGroupCoolDowns.put(serverId, channelGroupCoolDowns);
}
ACommand aCommand = commandManagementService.findCommandByName(commandName);
Long channelId = serverIdChannelId.getChannelId();
AChannel channel = channelManagementService.loadChannel(channelId);
List<AChannelGroup> channelGroups = channelGroupService.getChannelGroupsOfChannelWithType(channel, COOL_DOWN_CHANNEL_GROUP_TYPE);
List<AChannelGroupCommand> allChannelGroupsOfCommand =
channelGroupCommandService.getAllGroupCommandsForCommandInGroups(aCommand, channelGroups);
if (!allChannelGroupsOfCommand.isEmpty()) {
AChannelGroupCommand groupCommand = allChannelGroupsOfCommand.get(0);
if (allChannelGroupsOfCommand.size() > 1) {
log.info("Found multiple channel groups of type commandCoolDown for command {} in server {}. Taking the command group {}.",
command.getConfiguration().getName(), serverId, groupCommand.getCommandInGroupId());
}
Long channelGroupId = groupCommand.getGroup().getId();
if (channelGroupCoolDowns.containsKey(channelGroupId)) {
createReUseMapIfNotExists(newExecutionPoint, commandName, channelGroupCoolDowns, channelGroupId);
} else {
CommandReUseMap commandReUseMap = createCommandReUseMap(newExecutionPoint, commandName);
channelGroupCoolDowns.put(channelGroupId, commandReUseMap);
}
} else {
log.debug("Not adding a cool down on channel {} in server {}, because there is not channel group configured.",
channelId, serverId);
}
} finally {
if(takeLock) {
releaseLock();
}
}
}
private void createReUseMapIfNotExists(Instant newExecutionPoint, String commandName, Map<Long, CommandReUseMap> reuseMapMap, Long mapId) {
if (reuseMapMap.containsKey(mapId)) {
Map<String, Instant> reUseTimes = reuseMapMap.get(mapId).getReUseTimes();
reUseTimes.put(commandName, newExecutionPoint);
} else {
CommandReUseMap commandReUseMap = createCommandReUseMap(newExecutionPoint, commandName);
reuseMapMap.put(mapId, commandReUseMap);
}
}
@Override
public void addMemberCoolDown(Command command, AServerChannelUserId serverChannelUserId) {
addMemberCoolDown(command, serverChannelUserId, true);
}
@Override
public void addMemberCoolDown(Command command, AServerChannelUserId serverChannelUserId, boolean takeLock) {
if(takeLock) {
takeLock();
}
try {
Long serverId = serverChannelUserId.getGuildId();
Duration coolDown = getMemberCoolDownForCommand(command, serverChannelUserId.toServerChannelId());
Instant newExecutionPoint = Instant.now().plus(coolDown);
String commandName = command.getConfiguration().getName();
Map<Long, Map<Long, CommandReUseMap>> serverMemberCoolDowns = storage.getMemberCoolDowns();
Map<Long, CommandReUseMap> memberCoolDowns;
if(serverMemberCoolDowns.containsKey(serverId)) {
memberCoolDowns = serverMemberCoolDowns.get(serverId);
} else {
memberCoolDowns = new HashMap<>();
serverMemberCoolDowns.put(serverId, memberCoolDowns);
}
Long userId = serverChannelUserId.getUserId();
if (memberCoolDowns.containsKey(userId)) {
createReUseMapIfNotExists(newExecutionPoint, commandName, memberCoolDowns, userId);
} else {
CommandReUseMap commandReUseMap = createCommandReUseMap(newExecutionPoint, commandName);
memberCoolDowns.put(userId, commandReUseMap);
}
} finally {
if(takeLock) {
releaseLock();
}
}
}
@Override
public void updateCoolDowns(Command command, CommandContext context) {
takeLock();
try {
AServerChannelUserId contextIds = AServerChannelUserId
.builder()
.channelId(context.getChannel().getIdLong())
.userId(context.getAuthor().getIdLong())
.guildId(context.getGuild().getIdLong())
.build();
addServerCoolDown(command, contextIds.getGuildId(), false);
addChannelCoolDown(command, contextIds.toServerChannelId(), false);
addMemberCoolDown(command, contextIds, false);
} finally {
releaseLock();
}
}
@Override
public void setCoolDownConfigForChannelGroup(AChannelGroup aChannelGroup, Duration groupCoolDown, Duration memberCoolDown) {
CoolDownChannelGroup cdChannelGroup = coolDownChannelGroupManagementService.findByChannelGroupId(aChannelGroup.getId());
cdChannelGroup.setChannelCoolDown(groupCoolDown.getSeconds());
cdChannelGroup.setMemberCoolDown(memberCoolDown.getSeconds());
}
@Override
public void clearCoolDownsForServer(Long serverId) {
takeLock();
try {
storage.getServerCoolDowns().remove(serverId);
storage.getChannelGroupCoolDowns().remove(serverId);
storage.getMemberCoolDowns().remove(serverId);
} finally {
releaseLock();
}
}
private Duration getDurationToExecuteIn(Instant now, String commandName, CommandReUseMap reuseMap) {
if(reuseMap.getReUseTimes().containsKey(commandName)) {
Instant reUseTime = reuseMap.getReUseTimes().get(commandName);
return Duration.between(now, reUseTime);
}
return Duration.ZERO;
}
private CommandReUseMap createCommandReUseMap(Instant newExecutionPoint, String commandName) {
Map<String, Instant> reUseTimes = new HashMap<>();
reUseTimes.put(commandName, newExecutionPoint);
return CommandReUseMap.builder().reUseTimes(reUseTimes).build();
}
}

View File

@@ -0,0 +1,52 @@
package dev.sheldan.abstracto.core.command.service;
import dev.sheldan.abstracto.core.command.exception.CommandNotFoundException;
import dev.sheldan.abstracto.core.command.model.database.ACommand;
import dev.sheldan.abstracto.core.command.service.management.ChannelGroupCommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static dev.sheldan.abstracto.core.command.CommandConstants.COMMAND_CHANNEL_GROUP_KEY;
@Component
public class CommandDisabledServiceBean implements CommandDisabledService {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private ChannelGroupManagementService channelGroupManagementService;
@Autowired
private ChannelGroupCommandManagementService channelGroupCommandManagementService;
@Override
public void disableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
ACommand command = commandManagementService.findCommandByName(commandName);
if(command == null) {
throw new CommandNotFoundException();
}
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServerAndType(channelGroupName, server, COMMAND_CHANNEL_GROUP_KEY);
channelGroupCommandManagementService.setCommandInGroupTo(command, channelGroup, false);
}
@Override
public void enableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
ACommand command = commandManagementService.findCommandByName(commandName);
if(command == null) {
throw new CommandNotFoundException();
}
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServerAndType(channelGroupName, server, COMMAND_CHANNEL_GROUP_KEY);
channelGroupCommandManagementService.setCommandInGroupTo(command, channelGroup, true);
}
}

View File

@@ -1,8 +1,8 @@
package dev.sheldan.abstracto.core.command.service.management;
import dev.sheldan.abstracto.core.command.exception.CommandNotFoundInGroupException;
import dev.sheldan.abstracto.core.command.model.database.ACommand;
import dev.sheldan.abstracto.core.command.repository.ChannelGroupCommandRepository;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import lombok.extern.slf4j.Slf4j;
@@ -26,7 +26,23 @@ public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCom
groupCommand.setEnabled(enabled);
log.debug("Setting command {} enabled in group {} to {}.", command.getName(), group.getId(), enabled);
groupCommandRepository.save(groupCommand);
}
@Override
public void addCommandToGroup(ACommand command, AChannelGroup group) {
Optional<AChannelGroupCommand> groupCommandOptional = groupCommandRepository.findByCommandAndGroup(command, group);
if(!groupCommandOptional.isPresent()) {
createCommandInGroup(command, group);
}
}
@Override
public void removeCommandFromGroup(ACommand command, AChannelGroup group) {
Optional<AChannelGroupCommand> groupCommandOptional = groupCommandRepository.findByCommandAndGroup(command, group);
if(!groupCommandOptional.isPresent()) {
throw new CommandNotFoundInGroupException();
}
groupCommandOptional.ifPresent(channelGroupCommand -> groupCommandRepository.delete(channelGroupCommand));
}
@Override
@@ -36,7 +52,7 @@ public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCom
.command(command)
.server(group.getServer())
.group(group)
.enabled(false)
.enabled(true)
.build();
log.info("Creating command {} in group {}.", command.getName(), group.getId());
@@ -46,7 +62,7 @@ public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCom
@Override
public AChannelGroupCommand getChannelGroupCommand(ACommand command, AChannelGroup group) {
return groupCommandRepository.findByCommandAndGroup(command, group).orElseThrow(() -> new AbstractoRunTimeException("Command not found in group."));
return groupCommandRepository.findByCommandAndGroup(command, group).orElseThrow(CommandNotFoundInGroupException::new);
}
@Override
@@ -54,5 +70,14 @@ public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCom
return groupCommandRepository.findByCommand(command);
}
@Override
public List<AChannelGroupCommand> getAllGroupCommandsForCommandInGroups(ACommand command, List<AChannelGroup> groups) {
return groupCommandRepository.findByCommandAndGroupIn(command, groups);
}
@Override
public List<AChannelGroupCommand> getAllGroupCommandsForCommandWithType(ACommand command, String channelGroupType) {
return groupCommandRepository.findByCommandAndGroup_ChannelGroupType_GroupTypeKey(command, channelGroupType);
}
}

View File

@@ -0,0 +1,39 @@
package dev.sheldan.abstracto.core.command.service.management;
import dev.sheldan.abstracto.core.command.model.database.CommandDisabledChannelGroup;
import dev.sheldan.abstracto.core.command.repository.CommandDisabledChannelGroupRepository;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.service.management.CommandDisabledChannelGroupManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class CommandDisabledChannelGroupManagementServiceBean implements CommandDisabledChannelGroupManagementService {
@Autowired
private CommandDisabledChannelGroupRepository commandDisabledChannelGroupRepository;
@Override
public CommandDisabledChannelGroup createCommandDisabledChannelGroup(AChannelGroup channelGroup) {
CommandDisabledChannelGroup commandDisabledChannelGroup = CommandDisabledChannelGroup
.builder()
.channelGroup(channelGroup)
.id(channelGroup.getId())
.build();
log.info("Creating command disabled channel group for channel group {} in server {}.", channelGroup.getId(), channelGroup.getServer().getId());
return commandDisabledChannelGroupRepository.save(commandDisabledChannelGroup);
}
@Override
public void deleteCommandDisabledChannelGroup(AChannelGroup channelGroup) {
log.info("Deleting command disabled channel group for channel group {} in server {}.", channelGroup.getId(), channelGroup.getServer().getId());
commandDisabledChannelGroupRepository.deleteById(channelGroup.getId());
}
@Override
public CommandDisabledChannelGroup findViaChannelGroup(AChannelGroup channelGroup) {
return commandDisabledChannelGroupRepository.getOne(channelGroup.getId());
}
}

View File

@@ -24,6 +24,7 @@ public class CommandInServerManagementServiceBean implements CommandInServerMana
.commandReference(command)
.serverReference(server)
.restricted(false)
.coolDown(0L)
.build();
log.info("Creating command {} in server {}.", command.getName(), server.getId());
return repository.save(commandInAServer);

View File

@@ -0,0 +1,37 @@
package dev.sheldan.abstracto.core.command.service.management;
import dev.sheldan.abstracto.core.command.model.database.CoolDownChannelGroup;
import dev.sheldan.abstracto.core.command.repository.CoolDownChannelGroupRepository;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.service.management.CoolDownChannelGroupManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CoolDownChannelGroupManagementServiceBean implements CoolDownChannelGroupManagementService {
@Autowired
private CoolDownChannelGroupRepository repository;
@Override
public CoolDownChannelGroup createCoolDownChannelGroup(AChannelGroup aChannelGroup) {
CoolDownChannelGroup newChannelGroup = CoolDownChannelGroup
.builder()
.channelGroup(aChannelGroup)
.id(aChannelGroup.getId())
.memberCoolDown(0L)
.channelCoolDown(0L)
.build();
return repository.save(newChannelGroup);
}
@Override
public CoolDownChannelGroup findByChannelGroupId(Long channelGroupId) {
return repository.getOne(channelGroupId);
}
@Override
public void deleteCoolDownChannelGroup(AChannelGroup aChannelGroup) {
repository.delete(findByChannelGroupId(aChannelGroup.getId()));
}
}

View File

@@ -0,0 +1,53 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
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.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class AddCommandToChannelGroup extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;
@Override
public CommandResult execute(CommandContext commandContext) {
String channelGroupName = (String) commandContext.getParameters().getParameters().get(0);
String commandName = (String) commandContext.getParameters().getParameters().get(1);
channelGroupService.addCommandToChannelGroup(commandName, channelGroupName, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("channelGroupName").type(String.class).templated(true).build();
Parameter commandName = Parameter.builder().name("commandName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(channelGroupName, commandName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("addCommandToChannelGroup")
.module(ChannelsModuleDefinition.CHANNELS)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,51 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
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.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class DisableChannelGroup extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;
@Override
public CommandResult execute(CommandContext commandContext) {
String channelGroupName = (String) commandContext.getParameters().getParameters().get(0);
channelGroupService.disableChannelGroup(channelGroupName, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("channelGroupName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(channelGroupName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("disableChannelGroup")
.module(ChannelsModuleDefinition.CHANNELS)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -8,8 +8,8 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
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.CommandDisabledService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -20,21 +20,21 @@ import java.util.List;
public class DisableCommand extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;
private CommandDisabledService disableCommandInChannelGroup;
@Override
public CommandResult execute(CommandContext commandContext) {
String commandName = (String) commandContext.getParameters().getParameters().get(0);
String channelGroupName = (String) commandContext.getParameters().getParameters().get(1);
channelGroupService.disableCommandInChannelGroup(commandName, channelGroupName, commandContext.getGuild().getIdLong());
disableCommandInChannelGroup.disableCommandInChannelGroup(commandName, channelGroupName, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("commandName").type(String.class).templated(true).build();
Parameter channelToAdd = Parameter.builder().name("channelGroupName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(channelGroupName, channelToAdd);
Parameter commandName = Parameter.builder().name("commandName").type(String.class).templated(true).build();
Parameter channelGroupName = Parameter.builder().name("channelGroupName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(commandName, channelGroupName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build();
return CommandConfiguration.builder()
.name("disableCommand")

View File

@@ -0,0 +1,51 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
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.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class EnableChannelGroup extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;
@Override
public CommandResult execute(CommandContext commandContext) {
String channelGroupName = (String) commandContext.getParameters().getParameters().get(0);
channelGroupService.enableChannelGroup(channelGroupName, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("channelGroupName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(channelGroupName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("enableChannelGroup")
.module(ChannelsModuleDefinition.CHANNELS)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -8,8 +8,8 @@ import dev.sheldan.abstracto.core.command.config.Parameter;
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.CommandDisabledService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -20,21 +20,21 @@ import java.util.List;
public class EnableCommand extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;
private CommandDisabledService commandDisabledService;
@Override
public CommandResult execute(CommandContext commandContext) {
String commandName = (String) commandContext.getParameters().getParameters().get(0);
String channelGroupName = (String) commandContext.getParameters().getParameters().get(1);
channelGroupService.enableCommandInChannelGroup(commandName, channelGroupName, commandContext.getGuild().getIdLong());
commandDisabledService.enableCommandInChannelGroup(commandName, channelGroupName, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("commandName").type(String.class).templated(true).build();
Parameter channelToAdd = Parameter.builder().name("channelGroupName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(channelGroupName, channelToAdd);
Parameter commandName = Parameter.builder().name("commandName").type(String.class).templated(true).build();
Parameter channelGroupname = Parameter.builder().name("channelGroupName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(commandName, channelGroupname);
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build();
return CommandConfiguration.builder()
.name("enableCommand")

View File

@@ -10,22 +10,18 @@ import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.template.commands.ChannelGroupChannelModel;
import dev.sheldan.abstracto.core.models.template.commands.ChannelGroupModel;
import dev.sheldan.abstracto.core.models.template.commands.ListChannelGroupsModel;
import dev.sheldan.abstracto.core.service.ChannelGroupService;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
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 net.dv8tion.jda.api.entities.TextChannel;
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.Optional;
@Component
public class ListChannelGroups extends AbstractConditionableCommand {
@@ -42,41 +38,20 @@ public class ListChannelGroups extends AbstractConditionableCommand {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private ChannelGroupService channelGroupService;
@Override
public CommandResult execute(CommandContext commandContext) {
AServer server = serverManagementService.loadServer(commandContext.getGuild());
List<AChannelGroup> channelGroups = channelGroupManagementService.findAllInServer(server);
ListChannelGroupsModel template = (ListChannelGroupsModel) ContextConverter.fromCommandContext(commandContext, ListChannelGroupsModel.class);
template.setGroups(convertAChannelGroupToChannelGroupChannel(channelGroups));
template.setGroups(channelGroupService.convertAChannelGroupToChannelGroupChannel(channelGroups));
MessageToSend response = templateService.renderEmbedTemplate("listChannelGroups_response", template, commandContext.getGuild().getIdLong());
channelService.sendMessageToSendToChannel(response, commandContext.getChannel());
return CommandResult.fromIgnored();
}
private List<ChannelGroupModel> convertAChannelGroupToChannelGroupChannel(List<AChannelGroup> channelGroups) {
List<ChannelGroupModel> converted = new ArrayList<>();
channelGroups.forEach(group -> {
List<ChannelGroupChannelModel> convertedChannels = new ArrayList<>();
group.getChannels().forEach(channel -> {
Optional<TextChannel> textChannelInGuild = channelService.getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId());
ChannelGroupChannelModel convertedChannel = ChannelGroupChannelModel
.builder()
.channel(channel)
.discordChannel(textChannelInGuild.orElse(null))
.build();
convertedChannels.add(convertedChannel);
});
ChannelGroupModel channelGroup = ChannelGroupModel
.builder()
.name(group.getGroupName())
.typeKey(group.getChannelGroupType().getGroupTypeKey())
.channels(convertedChannels)
.build();
converted.add(channelGroup);
});
return converted;
}
@Override
public CommandConfiguration getConfiguration() {
List<String> aliases = Arrays.asList("lsChGrp");

View File

@@ -0,0 +1,53 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
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.config.FeatureDefinition;
import dev.sheldan.abstracto.core.service.ChannelGroupService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
@Component
public class RemoveCommandFromChannelGroup extends AbstractConditionableCommand {
@Autowired
private ChannelGroupService channelGroupService;
@Override
public CommandResult execute(CommandContext commandContext) {
String channelGroupName = (String) commandContext.getParameters().getParameters().get(0);
String commandName = (String) commandContext.getParameters().getParameters().get(1);
channelGroupService.removeCommandFromChannelGroup(commandName, channelGroupName, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("channelGroupName").type(String.class).templated(true).build();
Parameter commandName = Parameter.builder().name("commandName").type(String.class).templated(true).build();
List<Parameter> parameters = Arrays.asList(channelGroupName, commandName);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("removeCommandFromChannelGroup")
.module(ChannelsModuleDefinition.CHANNELS)
.parameters(parameters)
.supportsEmbedException(true)
.help(helpInfo)
.templated(true)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,43 @@
package dev.sheldan.abstracto.core.commands.config.cooldown;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
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.CommandCoolDownService;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ClearCommandCoolDowns extends AbstractConditionableCommand {
@Autowired
private CommandCoolDownService commandCoolDownService;
@Override
public CommandResult execute(CommandContext commandContext) {
commandCoolDownService.clearCoolDownsForServer(commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("clearCommandCoolDowns")
.module(ConfigModuleDefinition.CONFIG)
.templated(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,71 @@
package dev.sheldan.abstracto.core.commands.config.cooldown;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
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.CommandCoolDownService;
import dev.sheldan.abstracto.core.command.service.CommandCoolDownServiceBean;
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
@Component
public class CommandCoolDownChannelGroup extends AbstractConditionableCommand {
@Autowired
private ChannelGroupManagementService channelGroupManagementService;
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private CommandCoolDownService coolDownService;
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
AChannelGroup fakeChannelGroup = (AChannelGroup) parameters.get(0);
Duration channelDuration = (Duration) parameters.get(1);
Duration memberDuration = (Duration) parameters.get(2);
AServer actualServer = serverManagementService.loadServer(commandContext.getGuild().getIdLong());
AChannelGroup actualChannelGroup = channelGroupManagementService.findByNameAndServerAndType(
fakeChannelGroup.getGroupName(), actualServer, CommandCoolDownServiceBean.COOL_DOWN_CHANNEL_GROUP_TYPE);
coolDownService.setCoolDownConfigForChannelGroup(actualChannelGroup, channelDuration, memberDuration);
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("channelGroupName").templated(true).type(AChannelGroup.class).build();
Parameter channelDuration = Parameter.builder().name("channelDuration").templated(true).type(Duration.class).build();
Parameter memberDuration = Parameter.builder().name("memberDuration").templated(true).type(Duration.class).build();
List<Parameter> parameters = Arrays.asList(channelGroupName, channelDuration, memberDuration);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("commandCoolDownChannelGroup")
.module(ConfigModuleDefinition.CONFIG)
.parameters(parameters)
.templated(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -0,0 +1,63 @@
package dev.sheldan.abstracto.core.commands.config.cooldown;
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
import dev.sheldan.abstracto.core.command.config.HelpInfo;
import dev.sheldan.abstracto.core.command.config.Parameter;
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.model.database.ACommand;
import dev.sheldan.abstracto.core.command.model.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.commands.config.ConfigModuleDefinition;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
@Component
public class CommandCoolDownServer extends AbstractConditionableCommand {
@Autowired
private CommandInServerManagementService commandInServerManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Override
public CommandResult execute(CommandContext commandContext) {
List<Object> parameters = commandContext.getParameters().getParameters();
String commandName = (String) parameters.get(0);
ACommand aCommand = commandManagementService.findCommandByName(commandName);
Duration duration = (Duration) parameters.get(1);
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, commandContext.getGuild().getIdLong());
commandForServer.setCoolDown(duration.getSeconds());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter commandName = Parameter.builder().name("command").templated(true).type(String.class).build();
Parameter coolDownDuration = Parameter.builder().name("duration").templated(true).type(Duration.class).build();
List<Parameter> parameters = Arrays.asList(commandName, coolDownDuration);
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
return CommandConfiguration.builder()
.name("commandCoolDownServer")
.module(ConfigModuleDefinition.CONFIG)
.parameters(parameters)
.templated(true)
.help(helpInfo)
.causesReaction(true)
.build();
}
@Override
public FeatureDefinition getFeature() {
return CoreFeatureDefinition.CORE_FEATURE;
}
}

View File

@@ -8,16 +8,14 @@ import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.command.model.database.ACommand;
import dev.sheldan.abstracto.core.command.model.database.ACommandInAServer;
import dev.sheldan.abstracto.core.command.service.CommandInServerAliasService;
import dev.sheldan.abstracto.core.command.service.CommandRegistry;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.ModuleRegistry;
import dev.sheldan.abstracto.core.command.service.*;
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.config.FeatureDefinition;
import dev.sheldan.abstracto.core.metric.service.CounterMetric;
import dev.sheldan.abstracto.core.metric.service.MetricService;
import dev.sheldan.abstracto.core.metric.service.MetricTag;
import dev.sheldan.abstracto.core.models.ServerIdChannelId;
import dev.sheldan.abstracto.core.models.template.commands.help.HelpCommandDetailsModel;
import dev.sheldan.abstracto.core.models.template.commands.help.HelpModuleDetailsModel;
import dev.sheldan.abstracto.core.models.template.commands.help.HelpModuleOverviewModel;
@@ -31,6 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@@ -70,6 +69,9 @@ public class Help implements Command {
@Autowired
private CommandInServerAliasService commandInServerAliasService;
@Autowired
private CommandCoolDownService commandCoolDownService;
public static final String HELP_COMMAND_EXECUTED_METRIC = "help.executions";
public static final String CATEGORY = "category";
private static final CounterMetric HELP_COMMAND_NO_PARAMETER_METRIC =
@@ -133,12 +135,20 @@ public class Help implements Command {
if(commandOptional.isPresent()) {
metricService.incrementCounter(HELP_COMMAND_COMMAND_METRIC);
Command command = commandOptional.get();
ServerIdChannelId contextIds = ServerIdChannelId
.builder()
.channelId(commandContext.getChannel().getIdLong())
.serverId(commandContext.getGuild().getIdLong())
.build();
log.debug("Displaying help for command {}.", command.getConfiguration().getName());
ACommand aCommand = commandManagementService.findCommandByName(command.getConfiguration().getName());
List<String> aliases = commandInServerAliasService.getAliasesForCommand(commandContext.getGuild().getIdLong(), command.getConfiguration().getName());
ACommandInAServer aCommandInAServer = commandInServerManagementService.getCommandForServer(aCommand, commandContext.getGuild().getIdLong());
HelpCommandDetailsModel model = (HelpCommandDetailsModel) ContextConverter.fromCommandContext(commandContext, HelpCommandDetailsModel.class);
model.setServerSpecificAliases(aliases);
CommandCoolDownConfig coolDownConfig = getCoolDownConfig(command, contextIds);
model.setCooldowns(coolDownConfig);
if(Boolean.TRUE.equals(aCommandInAServer.getRestricted())) {
model.setImmuneRoles(roleService.getRolesFromGuild(aCommandInAServer.getImmuneRoles()));
model.setAllowedRoles(roleService.getRolesFromGuild(aCommandInAServer.getAllowedRoles()));
@@ -157,6 +167,24 @@ public class Help implements Command {
}
}
private CommandCoolDownConfig getCoolDownConfig(Command command, ServerIdChannelId contextIds) {
Duration serverCooldown = commandCoolDownService.getServerCoolDownForCommand(command, contextIds.getServerId());
Duration channelCooldown = commandCoolDownService.getChannelGroupCoolDownForCommand(command, contextIds);
Duration memberCooldown = commandCoolDownService.getMemberCoolDownForCommand(command, contextIds);
boolean hasMemberCooldown = !memberCooldown.equals(Duration.ZERO);
boolean hasServerCoolDown = !serverCooldown.equals(Duration.ZERO);
boolean hasChannelCoolDown = !channelCooldown.equals(Duration.ZERO);
if(!hasMemberCooldown && !hasServerCoolDown && !hasChannelCoolDown) {
return null;
}
return CommandCoolDownConfig
.builder()
.memberCoolDown(hasMemberCooldown ? memberCooldown : null)
.serverCoolDown(hasServerCoolDown ? serverCooldown: null)
.channelCoolDown(hasChannelCoolDown ? channelCooldown: null)
.build();
}
private CompletableFuture<CommandResult> displayHelpOverview(CommandContext commandContext) {
log.debug("Displaying help overview response.");
ModuleDefinition moduleDefinition = moduleService.getDefaultModule();

View File

@@ -107,11 +107,6 @@ public class ListenerExecutorConfig {
return executorService.setupExecutorFor("channelGroupCreatedListener");
}
@Bean(name = "channelGroupDeletedExecutor")
public TaskExecutor channelGroupDeletedExecutor() {
return executorService.setupExecutorFor("channelGroupDeletedListener");
}
@Bean(name = "serverJoinExecutor")
public TaskExecutor serverJoinExecutor() {
return executorService.setupExecutorFor("serverJoinListener");

View File

@@ -0,0 +1,32 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.listener.sync.entity.AsyncChannelGroupCreatedListener;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.listener.ChannelGroupCreatedListenerModel;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
import dev.sheldan.abstracto.core.service.management.CommandDisabledChannelGroupManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static dev.sheldan.abstracto.core.command.CommandConstants.COMMAND_CHANNEL_GROUP_KEY;
@Component
public class AsyncCommandDisabledChannelGroupCreatedListener implements AsyncChannelGroupCreatedListener {
@Autowired
private ChannelGroupManagementService channelGroupManagementService;
@Autowired
private CommandDisabledChannelGroupManagementService commandDisabledChannelGroupManagementService;
@Override
public DefaultListenerResult execute(ChannelGroupCreatedListenerModel model) {
AChannelGroup channelGroup = channelGroupManagementService.findChannelGroupById(model.getChannelGroupId());
if(channelGroup.getChannelGroupType().getGroupTypeKey().equals(COMMAND_CHANNEL_GROUP_KEY)) {
commandDisabledChannelGroupManagementService.createCommandDisabledChannelGroup(channelGroup);
return DefaultListenerResult.PROCESSED;
}
return DefaultListenerResult.IGNORED;
}
}

View File

@@ -0,0 +1,32 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.listener.sync.entity.AsyncChannelGroupCreatedListener;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.listener.ChannelGroupCreatedListenerModel;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
import dev.sheldan.abstracto.core.service.management.CoolDownChannelGroupManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static dev.sheldan.abstracto.core.command.service.CommandCoolDownServiceBean.COOL_DOWN_CHANNEL_GROUP_TYPE;
@Component
public class AsyncCoolDownChannelGroupCreatedListener implements AsyncChannelGroupCreatedListener {
@Autowired
private ChannelGroupManagementService channelGroupManagementService;
@Autowired
private CoolDownChannelGroupManagementService coolDownChannelGroupManagementService;
@Override
public DefaultListenerResult execute(ChannelGroupCreatedListenerModel model) {
AChannelGroup channelGroup = channelGroupManagementService.findChannelGroupById(model.getChannelGroupId());
if(channelGroup.getChannelGroupType().getGroupTypeKey().equals(COOL_DOWN_CHANNEL_GROUP_TYPE)) {
coolDownChannelGroupManagementService.createCoolDownChannelGroup(channelGroup);
return DefaultListenerResult.PROCESSED;
}
return DefaultListenerResult.IGNORED;
}
}

View File

@@ -0,0 +1,31 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.listener.sync.entity.ChannelGroupDeletedListener;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.listener.ChannelGroupDeletedListenerModel;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
import dev.sheldan.abstracto.core.service.management.CommandDisabledChannelGroupManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static dev.sheldan.abstracto.core.command.CommandConstants.COMMAND_CHANNEL_GROUP_KEY;
@Component
public class CommandDisabledChannelGroupDeletedListener implements ChannelGroupDeletedListener {
@Autowired
private ChannelGroupManagementService channelGroupManagementService;
@Autowired
private CommandDisabledChannelGroupManagementService commandDisabledChannelGroupManagementService;
@Override
public DefaultListenerResult execute(ChannelGroupDeletedListenerModel model) {
AChannelGroup channelGroup = channelGroupManagementService.findChannelGroupById(model.getChannelGroupId());
if(channelGroup.getChannelGroupType().getGroupTypeKey().equals(COMMAND_CHANNEL_GROUP_KEY)) {
commandDisabledChannelGroupManagementService.deleteCommandDisabledChannelGroup(channelGroup);
return DefaultListenerResult.PROCESSED;
}
return DefaultListenerResult.IGNORED;
}
}

View File

@@ -0,0 +1,31 @@
package dev.sheldan.abstracto.core.listener;
import dev.sheldan.abstracto.core.listener.sync.entity.ChannelGroupDeletedListener;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.listener.ChannelGroupDeletedListenerModel;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
import dev.sheldan.abstracto.core.service.management.CoolDownChannelGroupManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static dev.sheldan.abstracto.core.command.service.CommandCoolDownServiceBean.COOL_DOWN_CHANNEL_GROUP_TYPE;
@Component
public class CoolDownChannelGroupDeletedListener implements ChannelGroupDeletedListener {
@Autowired
private ChannelGroupManagementService channelGroupManagementService;
@Autowired
private CoolDownChannelGroupManagementService coolDownChannelGroupManagementService;
@Override
public DefaultListenerResult execute(ChannelGroupDeletedListenerModel model) {
AChannelGroup channelGroup = channelGroupManagementService.findChannelGroupById(model.getChannelGroupId());
if(channelGroup.getChannelGroupType().getGroupTypeKey().equals(COOL_DOWN_CHANNEL_GROUP_TYPE)) {
coolDownChannelGroupManagementService.deleteCoolDownChannelGroup(channelGroup);
return DefaultListenerResult.PROCESSED;
}
return DefaultListenerResult.IGNORED;
}
}

View File

@@ -1,33 +0,0 @@
package dev.sheldan.abstracto.core.listener.async.entity;
import dev.sheldan.abstracto.core.listener.ListenerService;
import dev.sheldan.abstracto.core.listener.sync.entity.AsyncChannelGroupDeletedListener;
import dev.sheldan.abstracto.core.models.listener.ChannelGroupDeletedListenerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionalEventListener;
import java.util.List;
@Component
public class AsyncChannelGroupDeletedListenerManager {
@Autowired(required = false)
private List<AsyncChannelGroupDeletedListener> listener;
@Autowired
private ListenerService listenerService;
@Autowired
@Qualifier("channelGroupDeletedExecutor")
private TaskExecutor channelGroupDeletedExecutor;
@TransactionalEventListener
public void executeListener(ChannelGroupDeletedListenerModel model){
listener.forEach(channelGroupCreatedListener ->
listenerService.executeListener(channelGroupCreatedListener, model, channelGroupDeletedExecutor)
);
}
}

View File

@@ -0,0 +1,27 @@
package dev.sheldan.abstracto.core.listener.sync.entity;
import dev.sheldan.abstracto.core.listener.ListenerService;
import dev.sheldan.abstracto.core.models.listener.ChannelGroupDeletedListenerModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Component
public class SyncChannelGroupDeletedListenerManager {
@Autowired(required = false)
private List<ChannelGroupDeletedListener> listener;
@Autowired
private ListenerService listenerService;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void executeListener(ChannelGroupDeletedListenerModel model){
listener.forEach(channelGroupCreatedListener ->
listenerService.executeListener(channelGroupCreatedListener, model)
);
}
}

View File

@@ -0,0 +1,39 @@
package dev.sheldan.abstracto.core.provider;
import dev.sheldan.abstracto.core.command.model.database.CoolDownChannelGroup;
import dev.sheldan.abstracto.core.models.provider.ChannelGroupInformationRequest;
import dev.sheldan.abstracto.core.models.provider.CoolDownChannelInformation;
import dev.sheldan.abstracto.core.models.provider.InformationRequest;
import dev.sheldan.abstracto.core.models.provider.ProviderInformation;
import dev.sheldan.abstracto.core.service.management.CoolDownChannelGroupManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import static dev.sheldan.abstracto.core.command.service.CommandCoolDownServiceBean.COOL_DOWN_CHANNEL_GROUP_TYPE;
@Component
public class CoolDownChannelGroupInformationProviderBean implements ChannelGroupInformationProvider {
@Autowired
private CoolDownChannelGroupManagementService coolDownChannelGroupManagementService;
@Override
public boolean handlesRequest(InformationRequest informationRequest) {
if(informationRequest instanceof ChannelGroupInformationRequest) {
ChannelGroupInformationRequest request = (ChannelGroupInformationRequest) informationRequest;
return request.getChannelGroupType().equals(COOL_DOWN_CHANNEL_GROUP_TYPE);
}
return false;
}
@Override
public ProviderInformation retrieveInformation(InformationRequest informationRequest) {
ChannelGroupInformationRequest request = (ChannelGroupInformationRequest) informationRequest;
CoolDownChannelGroup coolDownChannelGroup = coolDownChannelGroupManagementService.findByChannelGroupId(request.getChannelGroupId());
return CoolDownChannelInformation
.builder()
.channelCoolDown(coolDownChannelGroup.getChannelCoolDown())
.memberCoolDown(coolDownChannelGroup.getMemberCoolDown())
.build();
}
}

View File

@@ -12,7 +12,7 @@ import java.util.Optional;
@Repository
public interface ChannelGroupRepository extends JpaRepository<AChannelGroup, Long> {
Optional<AChannelGroup> findByGroupNameAndServer(String name, AServer server);
Optional<AChannelGroup> findByGroupNameIgnoreCaseAndServer(String name, AServer server);
Optional<AChannelGroup> findByGroupNameAndServerAndChannelGroupType_GroupTypeKey(String name, AServer server, String groupTyeKey);
@@ -20,7 +20,7 @@ public interface ChannelGroupRepository extends JpaRepository<AChannelGroup, Lon
List<AChannelGroup> findByServer(AServer server);
boolean existsByGroupNameAndServer(String name, AServer server);
boolean existsByGroupNameIgnoreCaseAndServer(String name, AServer server);
List<AChannelGroup> findAllByChannels(AChannel channel);
}

View File

@@ -8,5 +8,5 @@ import java.util.Optional;
@Repository
public interface ChannelGroupTypeRepository extends JpaRepository<ChannelGroupType, Integer> {
Optional<ChannelGroupType> findByGroupTypeKey(String key);
Optional<ChannelGroupType> findByGroupTypeKeyIgnoreCase(String key);
}

View File

@@ -5,23 +5,29 @@ import dev.sheldan.abstracto.core.command.exception.CommandNotFoundException;
import dev.sheldan.abstracto.core.command.model.database.ACommand;
import dev.sheldan.abstracto.core.command.service.management.ChannelGroupCommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.ChannelGroupType;
import dev.sheldan.abstracto.core.exception.ChannelInMultipleChannelGroupsException;
import dev.sheldan.abstracto.core.exception.CommandInMultipleChannelGroupsException;
import dev.sheldan.abstracto.core.models.database.*;
import dev.sheldan.abstracto.core.models.provider.ChannelGroupInformation;
import dev.sheldan.abstracto.core.models.provider.ChannelGroupInformationRequest;
import dev.sheldan.abstracto.core.models.template.commands.ChannelGroupChannelModel;
import dev.sheldan.abstracto.core.models.template.commands.ChannelGroupModel;
import dev.sheldan.abstracto.core.provider.ChannelGroupInformationProvider;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static dev.sheldan.abstracto.core.command.CommandConstants.COMMAND_CHANNEL_GROUP_KEY;
@Component
@Slf4j
public class ChannelGroupServiceBean implements ChannelGroupService {
@Autowired
@@ -39,6 +45,11 @@ public class ChannelGroupServiceBean implements ChannelGroupService {
@Autowired
private ServerManagementService serverManagementService;
@Autowired
private ChannelService channelService;
@Autowired
private List<ChannelGroupInformationProvider> channelGroupInformationProviders;
@Override
public AChannelGroup createChannelGroup(String name, Long serverId, ChannelGroupType channelGroupType) {
@@ -70,6 +81,12 @@ public class ChannelGroupServiceBean implements ChannelGroupService {
if(channelGroup == null) {
throw new ChannelGroupNotFoundException(channelGroupName, channelGroupManagementService.getAllAvailableAsString(server));
}
if(!channelGroup.getChannelGroupType().getAllowsChannelsInMultiple()) {
List<AChannelGroup> existingGroups = getChannelGroupsOfChannelWithType(channel, channelGroup.getChannelGroupType().getGroupTypeKey());
if(!existingGroups.isEmpty()) {
throw new ChannelInMultipleChannelGroupsException(existingGroups.get(0).getGroupName());
}
}
channelGroupManagementService.addChannelToChannelGroup(channelGroup, channel);
}
@@ -95,25 +112,50 @@ public class ChannelGroupServiceBean implements ChannelGroupService {
}
@Override
public void disableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId) {
public void addCommandToChannelGroup(String commandName, String channelGroupName, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServerAndType(channelGroupName, server, COMMAND_CHANNEL_GROUP_KEY);
ACommand command = commandManagementService.findCommandByName(commandName);
if(command == null) {
throw new CommandNotFoundException();
}
channelGroupCommandManagementService.setCommandInGroupTo(command, channelGroup, false);
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServer(channelGroupName, server);
if(!channelGroup.getChannelGroupType().getAllowsCommandsInMultiple()) {
List<AChannelGroupCommand> existingChannelGroupCommands = channelGroupCommandManagementService
.getAllGroupCommandsForCommandWithType(command, channelGroup.getChannelGroupType().getGroupTypeKey());
if(!existingChannelGroupCommands.isEmpty()) {
throw new CommandInMultipleChannelGroupsException(existingChannelGroupCommands.get(0).getGroup().getGroupName());
}
}
channelGroupCommandManagementService.addCommandToGroup(command, channelGroup);
log.info("Adding command {} to channel group {}.", command.getId(), channelGroup.getId());
}
@Override
public void enableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId) {
public void removeCommandFromChannelGroup(String commandName, String channelGroupName, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServerAndType(channelGroupName, server, COMMAND_CHANNEL_GROUP_KEY);
ACommand command = commandManagementService.findCommandByName(commandName);
if(command == null) {
throw new CommandNotFoundException();
}
channelGroupCommandManagementService.setCommandInGroupTo(command, channelGroup, true);
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServer(channelGroupName, server);
channelGroupCommandManagementService.removeCommandFromGroup(command, channelGroup);
log.info("Removing command {} from channel group {}.", command.getId(), channelGroup.getId());
}
@Override
public void disableChannelGroup(String channelGroupName, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServer(channelGroupName, server);
log.info("Disabling channel group {} in server {}.", channelGroup.getId(), serverId);
channelGroup.setEnabled(false);
}
@Override
public void enableChannelGroup(String channelGroupName, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServer(channelGroupName, server);
log.info("Enabling channel group {} in server {}.", channelGroup.getId(), serverId);
channelGroup.setEnabled(true);
}
@Override
@@ -130,4 +172,48 @@ public class ChannelGroupServiceBean implements ChannelGroupService {
.filter(aChannelGroup -> aChannelGroup.getChannelGroupType().getGroupTypeKey().equals(groupTypeKey))
.collect(Collectors.toList());
}
@Override
public List<ChannelGroupModel> convertAChannelGroupToChannelGroupChannel(List<AChannelGroup> channelGroups) {
List<ChannelGroupModel> converted = new ArrayList<>();
channelGroups.forEach(group -> {
List<ChannelGroupChannelModel> convertedChannels = new ArrayList<>();
group.getChannels().forEach(channel -> {
Optional<TextChannel> textChannelInGuild = channelService.getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId());
ChannelGroupChannelModel convertedChannel = ChannelGroupChannelModel
.builder()
.channel(channel)
.discordChannel(textChannelInGuild.orElse(null))
.build();
convertedChannels.add(convertedChannel);
});
ChannelGroupModel channelGroup = ChannelGroupModel
.builder()
.name(group.getGroupName())
.typeKey(group.getChannelGroupType().getGroupTypeKey())
.channels(convertedChannels)
.enabled(group.getEnabled())
.channelGroupInformation(getAdditionalInformation(group))
.build();
converted.add(channelGroup);
});
return converted;
}
private ChannelGroupInformation getAdditionalInformation(AChannelGroup channelGroup) {
if(channelGroupInformationProviders == null) {
return null;
}
ChannelGroupInformationRequest request = ChannelGroupInformationRequest
.builder()
.channelGroupId(channelGroup.getId())
.channelGroupType(channelGroup.getChannelGroupType().getGroupTypeKey())
.build();
for (ChannelGroupInformationProvider provider : channelGroupInformationProviders) {
if(provider.handlesRequest(request)) {
return provider.retrieveInformation(request);
}
}
return null;
}
}

View File

@@ -2,7 +2,7 @@ package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.command.exception.*;
import dev.sheldan.abstracto.core.listener.async.entity.AsyncChannelGroupCreatedListenerManager;
import dev.sheldan.abstracto.core.listener.async.entity.AsyncChannelGroupDeletedListenerManager;
import dev.sheldan.abstracto.core.listener.sync.entity.SyncChannelGroupDeletedListenerManager;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
@@ -31,7 +31,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
private ServerManagementService serverManagementService;
@Autowired
private AsyncChannelGroupDeletedListenerManager deletedListenerManager;
private SyncChannelGroupDeletedListenerManager deletedListenerManager;
@Autowired
private AsyncChannelGroupCreatedListenerManager createdListenerManager;
@@ -41,7 +41,6 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
@Override
public AChannelGroup createChannelGroup(String name, AServer server, ChannelGroupType channelGroupType) {
name = name.toLowerCase();
if(doesChannelGroupExist(name, server)) {
throw new ChannelGroupExistsException(name);
}
@@ -50,6 +49,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
.groupName(name)
.channelGroupType(channelGroupType)
.server(server)
.enabled(true)
.build();
log.info("Creating new channel group in server {}.", server.getId());
channelGroup = channelGroupRepository.save(channelGroup);
@@ -74,7 +74,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
@Override
public boolean doesChannelGroupExist(String name, AServer server) {
return channelGroupRepository.existsByGroupNameAndServer(name, server);
return channelGroupRepository.existsByGroupNameIgnoreCaseAndServer(name, server);
}
@Override
@@ -85,9 +85,11 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
throw new ChannelGroupNotFoundException(name, getAllAvailableAsString(server));
}
log.info("Deleting channel group {} in server {}.", existing.getId(), server.getId());
channelGroupRepository.delete(existing);
// we need to execute the _sync_ listeners before actually deleting it, in order to allow others to delete their instance
// this is a strong binding to listeners, might need to remove the direct connection at some point
ChannelGroupDeletedListenerModel model = getDeletionModel(existing);
applicationEventPublisher.publishEvent(model);
deletedListenerManager.executeListener(model);
channelGroupRepository.delete(existing);
}
@Override
@@ -126,13 +128,13 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
@Override
public AChannelGroup findByNameAndServer(String name, AServer server) {
String lowerCaseName = name.toLowerCase();
return channelGroupRepository.findByGroupNameAndServer(lowerCaseName, server)
return channelGroupRepository.findByGroupNameIgnoreCaseAndServer(lowerCaseName, server)
.orElseThrow(() -> new ChannelGroupNotFoundException(name, getAllAvailableAsString(server)));
}
@Override
public Optional<AChannelGroup> findByNameAndServerOptional(String name, AServer server) {
return channelGroupRepository.findByGroupNameAndServer(name, server);
return channelGroupRepository.findByGroupNameIgnoreCaseAndServer(name, server);
}
@Override
@@ -140,7 +142,7 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
String lowerName = name.toLowerCase();
Optional<AChannelGroup> channelOptional = channelGroupRepository.findByGroupNameAndServerAndChannelGroupType_GroupTypeKey(lowerName, server, expectedType);
return channelOptional.orElseThrow(() -> {
if(channelGroupRepository.existsByGroupNameAndServer(lowerName, server)) {
if(channelGroupRepository.existsByGroupNameIgnoreCaseAndServer(lowerName, server)) {
return new ChannelGroupIncorrectTypeException(name.toLowerCase(), expectedType);
} else {
List<String> channelGroupNames = extractChannelGroupNames(findAllInServerWithType(server.getId(), expectedType));

View File

@@ -18,7 +18,7 @@ public class ChannelGroupTypeManagementServiceBean implements ChannelGroupTypeMa
@Override
public Optional<ChannelGroupType> findChannelGroupTypeByKeyOptional(String key) {
return repository.findByGroupTypeKey(key);
return repository.findByGroupTypeKeyIgnoreCase(key);
}
@Override

View File

@@ -0,0 +1,11 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../dbchangelog-3.8.xsd" >
<include file="core-tables/tables.xml" relativeToChangelogFile="true"/>
<include file="core-seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="cool_down_channel_group_type-insertion">
<insert tableName="channel_group_type">
<column name="group_type_key" value="commandCoolDown"/>
<column name="allows_channel_in_multiple" value="false"/>
<column name="allows_commands_in_multiple" value="false"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,49 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<property name="coreFeature" value="(SELECT id FROM feature WHERE key = 'core')"/>
<property name="configModule" value="(SELECT id FROM module WHERE name = 'config')"/>
<property name="channelsModule" value="(SELECT id FROM module WHERE name = 'channels')"/>
<changeSet author="Sheldan" id="cool_down-commands" >
<insert tableName="command">
<column name="name" value="commandCoolDownChannelGroup"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="commandCoolDownServer"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="addCommandToChannelGroup"/>
<column name="module_id" valueComputed="${channelsModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="removeCommandFromChannelGroup"/>
<column name="module_id" valueComputed="${channelsModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="clearCommandCoolDowns"/>
<column name="module_id" valueComputed="${configModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="enableChannelGroup"/>
<column name="module_id" valueComputed="${channelsModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
<insert tableName="command">
<column name="name" value="disableChannelGroup"/>
<column name="module_id" valueComputed="${channelsModule}"/>
<column name="feature_id" valueComputed="${coreFeature}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,11 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<include file="command.xml" relativeToChangelogFile="true"/>
<include file="channel_group_type.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,20 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="channel_group_command-change_fk_to_channel_group">
<dropForeignKeyConstraint baseTableName="channel_group_command" constraintName="fk_channel_group_command_channel_group"/>
<addForeignKeyConstraint baseColumnNames="group_id" baseTableName="channel_group_command" constraintName="fk_channel_group_command_channel_group" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="channel_group" validate="true"/>
</changeSet>
<changeSet author="Sheldan" id="channel_group-add_enabled">
<addColumn tableName="channel_group" >
<column name="enabled" type="BOOLEAN" defaultValue="true"/>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,16 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="channel_group_type-add_allow_multiple_column">
<addColumn tableName="channel_group_type" >
<column name="allows_channel_in_multiple" type="boolean" defaultValue="true"/>
<column name="allows_commands_in_multiple" type="boolean" defaultValue="true"/>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,32 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="command_disabled_channel_group-table">
<createTable tableName="command_disabled_channel_group">
<column name="id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
</createTable>
<addForeignKeyConstraint baseColumnNames="id" baseTableName="command_disabled_channel_group" constraintName="fk_command_disabled_channel_group_group_group"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="channel_group" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS command_disabled_channel_group_update_trigger ON command_disabled_channel_group;
CREATE TRIGGER repost_check_channel_group_update_trigger BEFORE UPDATE ON command_disabled_channel_group FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
</sql>
<sql>
DROP TRIGGER IF EXISTS command_disabled_channel_group_insert_trigger ON command_disabled_channel_group;
CREATE TRIGGER repost_check_channel_group_insert_trigger BEFORE INSERT ON command_disabled_channel_group FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,15 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="command_in_server-add_cool_down_column">
<addColumn tableName="command_in_server" >
<column name="cool_down" type="integer" defaultValue="0"/>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,38 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<changeSet author="Sheldan" id="cool_down_channel_group-table">
<createTable tableName="cool_down_channel_group">
<column name="id" type="BIGINT">
<constraints nullable="true"/>
</column>
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
<constraints nullable="true"/>
</column>
<column name="updated" type="TIMESTAMP WITHOUT TIME ZONE"/>
<column name="channel_cool_down" type="integer">
<constraints nullable="true"/>
</column>
<column name="member_cool_down" type="integer">
<constraints nullable="true"/>
</column>
</createTable>
<addForeignKeyConstraint baseColumnNames="id" baseTableName="cool_down_channel_group" constraintName="fk_cool_down_channel_group_group_group"
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="channel_group" validate="true"/>
<sql>
DROP TRIGGER IF EXISTS cool_down_channel_group_update_trigger ON cool_down_channel_group;
CREATE TRIGGER repost_check_channel_group_update_trigger BEFORE UPDATE ON cool_down_channel_group FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
</sql>
<sql>
DROP TRIGGER IF EXISTS cool_down_channel_group_insert_trigger ON cool_down_channel_group;
CREATE TRIGGER repost_check_channel_group_insert_trigger BEFORE INSERT ON cool_down_channel_group FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
</sql>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,14 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
<include file="channel_group.xml" relativeToChangelogFile="true"/>
<include file="channel_group_type.xml" relativeToChangelogFile="true"/>
<include file="cool_down_channel_group.xml" relativeToChangelogFile="true"/>
<include file="command_disabled_channel_group.xml" relativeToChangelogFile="true"/>
<include file="command_in_server.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -9,8 +9,9 @@
<include file="1.0-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.0-templating/collection.xml" relativeToChangelogFile="true"/>
<include file="1.1-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.0-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.5-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.7-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.8-core/collection.xml" relativeToChangelogFile="true"/>
<include file="1.2.9-core/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -7,6 +7,7 @@ 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.requests.RestAction;
import net.dv8tion.jda.internal.utils.concurrent.task.GatewayTask;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -76,28 +77,33 @@ public class MemberParameterHandlerImplTest extends AbstractParameterHandlerTest
Assert.assertEquals(member, parsed.join());
}
@Test(expected = AbstractoTemplatedException.class)
@Test
public void testNotExistingMember() {
String input = "test";
when(message.getGuild()).thenReturn(guild);
when(guild.getMembersByName(input, true)).thenReturn(new ArrayList<>());
testUnit.handleAsync(getPieceWithValue(input), null, parameter, message, command);
GatewayTask task = new GatewayTask(CompletableFuture.completedFuture(new ArrayList()), () -> {});
when(guild.retrieveMembersByPrefix(input, 1)).thenReturn(task);
CompletableFuture<Object> future = testUnit.handleAsync(getPieceWithValue(input), null, parameter, message, command);
Assert.assertTrue(future.isCompletedExceptionally());
}
@Test(expected = AbstractoTemplatedException.class)
@Test
public void testMultipleFoundMemberByName() {
String input = "test";
Member secondMember = Mockito.mock(Member.class);
when(message.getGuild()).thenReturn(guild);
when(guild.getMembersByName(input, true)).thenReturn(Arrays.asList(member, secondMember));
testUnit.handleAsync(getPieceWithValue(input), null, parameter, message, command);
GatewayTask task = new GatewayTask(CompletableFuture.completedFuture(Arrays.asList(member, secondMember)), () -> {});
when(guild.retrieveMembersByPrefix(input, 1)).thenReturn(task);
CompletableFuture<Object> future = testUnit.handleAsync(getPieceWithValue(input), null, parameter, message, command);
Assert.assertTrue(future.isCompletedExceptionally());
}
@Test
public void testFindMemberByName() {
String input = "test";
when(message.getGuild()).thenReturn(guild);
when(guild.getMembersByName(input, true)).thenReturn(Arrays.asList(member));
GatewayTask task = new GatewayTask(CompletableFuture.completedFuture(Arrays.asList(member)), () -> {});
when(guild.retrieveMembersByPrefix(input, 1)).thenReturn(task);
CompletableFuture<Object> future = testUnit.handleAsync(getPieceWithValue(input), null, parameter, message, command);
Member returnedMember = (Member) future.join();
Assert.assertFalse(future.isCompletedExceptionally());

View File

@@ -16,6 +16,7 @@ import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Arrays;
import static dev.sheldan.abstracto.core.command.CommandConstants.COMMAND_CHANNEL_GROUP_KEY;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
@@ -50,14 +51,15 @@ public class ChannelGroupCommandServiceBeanTest {
@Test
public void testNoChannelGroup() {
when(channelGroupCommandService.getAllGroupCommandsForCommand(command)).thenReturn(new ArrayList<>());
when(channelGroupCommandService.getAllGroupCommandsForCommandWithType(command, COMMAND_CHANNEL_GROUP_KEY)).thenReturn(new ArrayList<>());
Assert.assertTrue(testUnit.isCommandEnabled(command, channel));
}
@Test
public void testOneDisabledChannelGroup() {
when(channelGroupCommandService.getAllGroupCommandsForCommand(command)).thenReturn(Arrays.asList(channelGroupCommand));
when(channelGroupCommandService.getAllGroupCommandsForCommandWithType(command, COMMAND_CHANNEL_GROUP_KEY)).thenReturn(Arrays.asList(channelGroupCommand));
when(channelGroupCommand.getGroup()).thenReturn(channelGroup);
when(channelGroup.getEnabled()).thenReturn(true);
when(channelGroup.getChannels()).thenReturn(Arrays.asList(channel));
when(channelGroupCommand.getEnabled()).thenReturn(false);
Assert.assertFalse(testUnit.isCommandEnabled(command, channel));
@@ -65,8 +67,9 @@ public class ChannelGroupCommandServiceBeanTest {
@Test
public void testOneEnabledChannelGroup() {
when(channelGroupCommandService.getAllGroupCommandsForCommand(command)).thenReturn(Arrays.asList(channelGroupCommand));
when(channelGroupCommandService.getAllGroupCommandsForCommandWithType(command, COMMAND_CHANNEL_GROUP_KEY)).thenReturn(Arrays.asList(channelGroupCommand));
when(channelGroupCommand.getGroup()).thenReturn(channelGroup);
when(channelGroup.getEnabled()).thenReturn(true);
when(channelGroup.getChannels()).thenReturn(Arrays.asList(channel));
when(channelGroupCommand.getEnabled()).thenReturn(true);
Assert.assertTrue(testUnit.isCommandEnabled(command, channel));
@@ -74,8 +77,9 @@ public class ChannelGroupCommandServiceBeanTest {
@Test
public void testDisabledInOneGroupChannelIsNotPartOf() {
when(channelGroupCommandService.getAllGroupCommandsForCommand(command)).thenReturn(Arrays.asList(channelGroupCommand));
when(channelGroupCommandService.getAllGroupCommandsForCommandWithType(command, COMMAND_CHANNEL_GROUP_KEY)).thenReturn(Arrays.asList(channelGroupCommand));
when(channelGroupCommand.getGroup()).thenReturn(channelGroup);
when(channelGroup.getEnabled()).thenReturn(true);
when(channelGroup.getChannels()).thenReturn(Arrays.asList(secondChannel));
when(channel.getId()).thenReturn(CHANNEL_ID);
when(secondChannel.getId()).thenReturn(CHANNEL_ID_2);

View File

@@ -32,10 +32,14 @@ public abstract class AbstractConditionableCommand implements ConditionalCommand
@Autowired
private AdminModeCondition adminModeCondition;
@Autowired
private CommandCoolDownCondition coolDownCondition;
@Override
public List<CommandCondition> getConditions() {
return new ArrayList<>(Arrays.asList(adminModeCondition, featureEnabledCondition, commandDisabledCondition, commandDisallowedCondition, featureModeCondition));
return new ArrayList<>(Arrays.asList(adminModeCondition, featureEnabledCondition, commandDisabledCondition,
commandDisallowedCondition, featureModeCondition, coolDownCondition));
}
protected void checkParameters(CommandContext context) {

View File

@@ -0,0 +1,36 @@
package dev.sheldan.abstracto.core.command.condition;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.condition.detail.CommandCoolDownDetail;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CoolDownCheckResult;
import dev.sheldan.abstracto.core.command.service.CommandCoolDownService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.Duration;
@Component
public class CommandCoolDownCondition implements CommandCondition {
@Autowired
private CommandCoolDownService commandCoolDownService;
@Override
public ConditionResult shouldExecute(CommandContext commandContext, Command command) {
commandCoolDownService.takeLock();
try {
CoolDownCheckResult result = commandCoolDownService.allowedToExecuteCommand(command, commandContext);
if(result.getCanExecute()) {
return ConditionResult.builder().result(true).build();
} else {
if(result.getExecuteIn().compareTo(Duration.ofSeconds(1)) < 0) {
result.setExecuteIn(Duration.ofSeconds(1));
}
return ConditionResult.builder().result(false).conditionDetail(new CommandCoolDownDetail(result)).build();
}
} finally {
commandCoolDownService.releaseLock();
}
}
}

View File

@@ -0,0 +1,24 @@
package dev.sheldan.abstracto.core.command.condition.detail;
import dev.sheldan.abstracto.core.command.condition.ConditionDetail;
import dev.sheldan.abstracto.core.command.execution.CoolDownCheckResult;
import dev.sheldan.abstracto.core.command.model.condition.CommandCoolDownDetailModel;
public class CommandCoolDownDetail implements ConditionDetail {
private final CommandCoolDownDetailModel model;
public CommandCoolDownDetail(CoolDownCheckResult result) {
this.model = CommandCoolDownDetailModel.builder().reason(result).build();
}
@Override
public String getTemplateName() {
return "command_cool_down_detail";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -32,6 +32,8 @@ public class CommandConfiguration {
private boolean templated = false;
private HelpInfo help;
private CommandCoolDownConfig coolDownConfig;
public int getNecessaryParameterCount(){
return (int) parameters.stream().filter(parameter -> !parameter.isOptional()).count();
}

View File

@@ -0,0 +1,16 @@
package dev.sheldan.abstracto.core.command.config;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.time.Duration;
@Getter
@Setter
@Builder
public class CommandCoolDownConfig {
private Duration serverCoolDown;
private Duration channelCoolDown;
private Duration memberCoolDown;
}

View File

@@ -14,7 +14,7 @@ public class ChannelGroupIncorrectTypeException extends AbstractoRunTimeExceptio
}
@Override
public String getTemplateName() {
return "channel_group_not_found_exception";
return "channel_group_incorrect_type_exception";
}
@Override

View File

@@ -9,6 +9,7 @@ public class CommandAliasAlreadyExistsException extends AbstractoRunTimeExceptio
private final CommandAliasAlreadyExistsModel model;
public CommandAliasAlreadyExistsException(String existingCommand) {
super("Command alias already exists.");
this.model = CommandAliasAlreadyExistsModel
.builder()
.existingCommand(existingCommand)

View File

@@ -2,11 +2,13 @@ package dev.sheldan.abstracto.core.command.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class CommandAliasDoesNotExistsException extends AbstractoRunTimeException implements Templatable {
public CommandAliasDoesNotExistsException() {
super("Command Alias does not exist.");
}
@Override
public String getTemplateName() {
return "command_in_server_alias_not_exists_exists_exception";

View File

@@ -9,6 +9,7 @@ public class CommandAliasHidesCommandException extends AbstractoRunTimeException
private final CommandAliasHidesCommandModel model;
public CommandAliasHidesCommandException(String existingCommand) {
super("Command alias hides existing command");
this.model = CommandAliasHidesCommandModel
.builder()
.existingCommand(existingCommand)

View File

@@ -0,0 +1,21 @@
package dev.sheldan.abstracto.core.command.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.templating.Templatable;
public class CommandNotFoundInGroupException extends AbstractoRunTimeException implements Templatable {
public CommandNotFoundInGroupException() {
super("Command was not found in given group.");
}
@Override
public String getTemplateName() {
return "command_not_found_in_group_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -17,6 +17,7 @@ public class CommandParameterValidationException extends AbstractoRunTimeExcepti
private final CommandParameterValidationExceptionModel model;
public CommandParameterValidationException(List<ValidatorParam> validatorParams, String template, Parameter parameter) {
super("Command parameter failed to validate.");
this.model = CommandParameterValidationExceptionModel
.builder()
.validationTemplate(template)

View File

@@ -12,7 +12,12 @@ public class IncorrectFeatureModeException extends AbstractoRunTimeException imp
private final IncorrectFeatureModeModel model;
public IncorrectFeatureModeException(FeatureDefinition featureDefinition, List<FeatureMode> requiredModes) {
this.model = IncorrectFeatureModeModel.builder().featureDefinition(featureDefinition).requiredModes(requiredModes).build();
super("Incorrect feature mode.");
this.model = IncorrectFeatureModeModel
.builder()
.featureDefinition(featureDefinition)
.requiredModes(requiredModes)
.build();
}
@Override

View File

@@ -11,7 +11,11 @@ public class IncorrectParameterException extends AbstractoRunTimeException imple
public IncorrectParameterException(Command command, String parameterName) {
super("Incorrect parameter given for parameter");
this.model = IncorrectParameterExceptionModel.builder().parameterName(parameterName).command(command).build();
this.model = IncorrectParameterExceptionModel
.builder()
.parameterName(parameterName)
.command(command)
.build();
}
@Override

View File

@@ -0,0 +1,54 @@
package dev.sheldan.abstracto.core.command.execution;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.time.Duration;
@Getter
@Setter
@Builder
public class CoolDownCheckResult {
private Duration executeIn;
private Boolean canExecute;
private CoolDownReason reason;
public static CoolDownCheckResult getServerCoolDown(Duration duration) {
return CoolDownCheckResult
.builder()
.canExecute(false)
.reason(CoolDownReason.SERVER)
.executeIn(duration)
.build();
}
public static CoolDownCheckResult getChannelGroupCoolDown(Duration duration) {
return CoolDownCheckResult
.builder()
.canExecute(false)
.reason(CoolDownReason.CHANNEL_GROUP)
.executeIn(duration)
.build();
}
public static CoolDownCheckResult getMemberCoolDown(Duration duration) {
return CoolDownCheckResult
.builder()
.canExecute(false)
.reason(CoolDownReason.MEMBER)
.executeIn(duration)
.build();
}
public static CoolDownCheckResult noCoolDown() {
return CoolDownCheckResult
.builder()
.canExecute(true)
.build();
}
}
enum CoolDownReason {
SERVER, CHANNEL_GROUP, MEMBER
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.command.model.condition;
import dev.sheldan.abstracto.core.command.execution.CoolDownCheckResult;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
@Getter
@Setter
@Builder
public class CommandCoolDownDetailModel implements Serializable {
private CoolDownCheckResult reason;
}

View File

@@ -61,6 +61,9 @@ public class ACommandInAServer implements Serializable {
@Column(name = "updated")
private Instant updated;
@Column(name = "cool_down")
private Long coolDown;
}

View File

@@ -0,0 +1,31 @@
package dev.sheldan.abstracto.core.command.model.database;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import lombok.*;
import javax.persistence.*;
import java.time.Instant;
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "command_disabled_channel_group")
@Getter
@Setter
@EqualsAndHashCode
public class CommandDisabledChannelGroup {
@Id
@Column(name = "id")
private Long id;
@OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@PrimaryKeyJoinColumn
private AChannelGroup channelGroup;
@Column(name = "created")
private Instant created;
@Column(name = "updated")
private Instant updated;
}

View File

@@ -0,0 +1,37 @@
package dev.sheldan.abstracto.core.command.model.database;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import lombok.*;
import javax.persistence.*;
import java.time.Instant;
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "cool_down_channel_group")
@Getter
@Setter
@EqualsAndHashCode
public class CoolDownChannelGroup {
@Id
@Column(name = "id")
private Long id;
@OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@PrimaryKeyJoinColumn
private AChannelGroup channelGroup;
@Column(name = "channel_cool_down")
private Long channelCoolDown;
@Column(name = "member_cool_down")
private Long memberCoolDown;
@Column(name = "created")
private Instant created;
@Column(name = "updated")
private Instant updated;
}

View File

@@ -0,0 +1,39 @@
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.CoolDownCheckResult;
import dev.sheldan.abstracto.core.command.model.database.ACommand;
import dev.sheldan.abstracto.core.models.AServerChannelUserId;
import dev.sheldan.abstracto.core.models.ServerIdChannelId;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import java.time.Duration;
public interface CommandCoolDownService {
/**
* Acquires the lock which should be used when accessing the runtime storage
*/
void takeLock();
/**
* Releases the lock which should be used then accessing the runtime storage
*/
void releaseLock();
CoolDownCheckResult allowedToExecuteCommand(Command command, CommandContext context);
Duration getServerCoolDownForCommand(Command command, Long serverId);
Duration getServerCoolDownForCommand(ACommand aCommand, Command command, Long serverId);
Duration getChannelGroupCoolDownForCommand(Command command, ServerIdChannelId serverIdChannelId);
Duration getChannelGroupCoolDownForCommand(ACommand aCommand, Command command, ServerIdChannelId serverIdChannelId);
Duration getMemberCoolDownForCommand(Command command, ServerIdChannelId serverIdChannelId);
Duration getMemberCoolDownForCommand(ACommand aCommand, Command command, ServerIdChannelId serverIdChannelId);
void addServerCoolDown(Command command, Long serverId);
void addServerCoolDown(Command command, Long serverId, boolean takeLock);
void addChannelCoolDown(Command command, ServerIdChannelId context);
void addChannelCoolDown(Command command, ServerIdChannelId context, boolean takeLock);
void addMemberCoolDown(Command command, AServerChannelUserId context);
void addMemberCoolDown(Command command, AServerChannelUserId context, boolean takeLock);
void updateCoolDowns(Command command, CommandContext context);
void setCoolDownConfigForChannelGroup(AChannelGroup aChannelGroup, Duration groupCoolDown, Duration memberCoolDown);
void clearCoolDownsForServer(Long serverId);
}

View File

@@ -0,0 +1,6 @@
package dev.sheldan.abstracto.core.command.service;
public interface CommandDisabledService {
void disableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId);
void enableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId);
}

View File

@@ -8,7 +8,11 @@ import java.util.List;
public interface ChannelGroupCommandManagementService {
void setCommandInGroupTo(ACommand command, AChannelGroup group, Boolean enabled);
void addCommandToGroup(ACommand command, AChannelGroup group);
void removeCommandFromGroup(ACommand command, AChannelGroup group);
AChannelGroupCommand createCommandInGroup(ACommand command, AChannelGroup group);
AChannelGroupCommand getChannelGroupCommand(ACommand command, AChannelGroup group);
List<AChannelGroupCommand> getAllGroupCommandsForCommand(ACommand command);
List<AChannelGroupCommand> getAllGroupCommandsForCommandInGroups(ACommand command, List<AChannelGroup> groups);
List<AChannelGroupCommand> getAllGroupCommandsForCommandWithType(ACommand command, String channelGroupType);
}

View File

@@ -9,7 +9,11 @@ public class CategoryNotFoundException extends AbstractoRunTimeException impleme
public CategoryNotFoundException(Long categoryId, Long guildId) {
super("Category not found");
this.model = CategoryNotFoundExceptionModel.builder().categoryId(categoryId).guildId(guildId).build();
this.model = CategoryNotFoundExceptionModel
.builder()
.categoryId(categoryId)
.guildId(guildId)
.build();
}
@Override

View File

@@ -10,7 +10,11 @@ public class ChannelGroupTypeNotFound extends AbstractoRunTimeException implemen
private final ChannelGroupTypeNotFoundExceptionModel model;
public ChannelGroupTypeNotFound(List<String> channelGroupTypeKeys) {
this.model = ChannelGroupTypeNotFoundExceptionModel.builder().availableGroupTypeKeys(channelGroupTypeKeys).build();
super("Channel group type not found.");
this.model = ChannelGroupTypeNotFoundExceptionModel
.builder()
.availableGroupTypeKeys(channelGroupTypeKeys)
.build();
}
@Override

View File

@@ -0,0 +1,27 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.models.exception.ChannelInMultipleChannelGroupsExceptionModel;
import dev.sheldan.abstracto.core.templating.Templatable;
public class ChannelInMultipleChannelGroupsException extends AbstractoRunTimeException implements Templatable {
private final ChannelInMultipleChannelGroupsExceptionModel model;
public ChannelInMultipleChannelGroupsException(String channelGroupName) {
super("Channel is already in another group of this type.");
this.model = ChannelInMultipleChannelGroupsExceptionModel
.builder()
.channelGroupName(channelGroupName)
.build();
}
@Override
public String getTemplateName() {
return "channel_in_multiple_channel_groups_exception";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -9,7 +9,10 @@ public class ChannelNotFoundException extends AbstractoRunTimeException implemen
public ChannelNotFoundException(Long channelId) {
super("Channel not found in database");
this.model = ChannelNotFoundExceptionModel.builder().channelId(channelId).build();
this.model = ChannelNotFoundExceptionModel
.builder()
.channelId(channelId)
.build();
}
@Override

View File

@@ -9,7 +9,10 @@ public class ChannelNotInGuildException extends AbstractoRunTimeException implem
public ChannelNotInGuildException(Long channelId) {
super("Channel not found in guild");
this.model = ChannelNotFoundExceptionModel.builder().channelId(channelId).build();
this.model = ChannelNotFoundExceptionModel
.builder()
.channelId(channelId)
.build();
}
@Override

View File

@@ -0,0 +1,27 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.models.exception.CommandInMultipleChannelGroupsExceptionModel;
import dev.sheldan.abstracto.core.templating.Templatable;
public class CommandInMultipleChannelGroupsException extends AbstractoRunTimeException implements Templatable {
private final CommandInMultipleChannelGroupsExceptionModel model;
public CommandInMultipleChannelGroupsException(String channelGroupName) {
super("Command is already in another group of this type.");
this.model = CommandInMultipleChannelGroupsExceptionModel
.builder()
.channelGroupName(channelGroupName)
.build();
}
@Override
public String getTemplateName() {
return "command_in_multiple_channel_groups_exception";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -9,7 +9,10 @@ public class ConfigurationKeyNotFoundException extends AbstractoRunTimeException
public ConfigurationKeyNotFoundException(String key) {
super("Configuration key not found");
this.model = ConfigurationKeyNotFoundExceptionModel.builder().key(key).build();
this.model = ConfigurationKeyNotFoundExceptionModel
.builder()
.key(key)
.build();
}
@Override

View File

@@ -10,7 +10,10 @@ public class ConfiguredEmoteNotUsableException extends AbstractoRunTimeException
public ConfiguredEmoteNotUsableException(AEmote emote) {
super("Emote was configured in database, but is not usable by the bot anymore.");
this.model = EmoteConfiguredButNotUsableExceptionModel.builder().emote(emote).build();
this.model = EmoteConfiguredButNotUsableExceptionModel
.builder()
.emote(emote)
.build();
}
@Override

View File

@@ -12,7 +12,11 @@ public class DurationFormatException extends AbstractoRunTimeException implement
public DurationFormatException(String wrongFormat, List<String> validFormats) {
super("Duration format exception ");
this.model = DurationFormatExceptionModel.builder().invalidFormat(wrongFormat).validFormats(validFormats).build();
this.model = DurationFormatExceptionModel
.builder()
.invalidFormat(wrongFormat)
.validFormats(validFormats)
.build();
}
@Override

View File

@@ -9,7 +9,10 @@ public class EmoteNotDefinedException extends AbstractoRunTimeException implemen
public EmoteNotDefinedException(String key) {
super(String.format("Emote %s not defined", key));
this.model = EmoteNotDefinedExceptionModel.builder().emoteKey(key).build();
this.model = EmoteNotDefinedExceptionModel
.builder()
.emoteKey(key)
.build();
}
@Override

View File

@@ -11,7 +11,11 @@ public class EmoteNotFoundException extends AbstractoRunTimeException implements
public EmoteNotFoundException(String key, List<String> availableEmotes) {
super("Emote not found");
this.model = EmoteNotFoundExceptionModel.builder().emoteKey(key).available(availableEmotes).build();
this.model = EmoteNotFoundExceptionModel
.builder()
.emoteKey(key)
.available(availableEmotes)
.build();
}
@Override

View File

@@ -9,7 +9,10 @@ public class EmoteNotFoundInDbException extends AbstractoRunTimeException implem
public EmoteNotFoundInDbException(Integer emoteId) {
super("Emote not found in database");
this.model = EmoteNotFoundInDbExceptionModel.builder().emoteId(emoteId).build();
this.model = EmoteNotFoundInDbExceptionModel
.builder()
.emoteId(emoteId)
.build();
}
@Override

View File

@@ -9,7 +9,10 @@ public class EmoteNotInServerException extends AbstractoRunTimeException impleme
public EmoteNotInServerException(Long emoteId) {
super("Emote not available in server");
this.model = EmoteNotInServerExceptionModel.builder().emoteId(emoteId).build();
this.model = EmoteNotInServerExceptionModel
.builder()
.emoteId(emoteId)
.build();
}
@Override

View File

@@ -10,7 +10,10 @@ public class EmoteNotUsableException extends AbstractoRunTimeException implement
public EmoteNotUsableException(Emote emote) {
super(String.format("Emote %s not usable by bot.", emote.getId()));
this.model = EmoteNotUsableExceptionModel.builder().emote(emote).build();
this.model = EmoteNotUsableExceptionModel
.builder()
.emote(emote)
.build();
}
@Override

View File

@@ -11,7 +11,11 @@ public class FeatureModeNotFoundException extends AbstractoRunTimeException impl
public FeatureModeNotFoundException(String featureMode, List<String> availableModes) {
super("Feature mode not found.");
this.model = FeatureModeNotFoundExceptionModel.builder().availableModes(availableModes).featureMode(featureMode).build();
this.model = FeatureModeNotFoundExceptionModel
.builder()
.availableModes(availableModes)
.featureMode(featureMode)
.build();
}
@Override

View File

@@ -11,8 +11,11 @@ public class FeatureNotFoundException extends AbstractoRunTimeException implemen
public FeatureNotFoundException(String feature, List<String> availableFeatures) {
super("Feature not found.");
this.model = FeatureNotFoundExceptionModel.builder().featureName(feature).availableFeatures(availableFeatures).build();
this.model = FeatureNotFoundExceptionModel
.builder()
.featureName(feature)
.availableFeatures(availableFeatures)
.build();
}
@Override

View File

@@ -8,7 +8,10 @@ public class GuildNotFoundException extends AbstractoRunTimeException implements
public GuildNotFoundException(Long guildId) {
super("Guild not found");
this.model = GuildNotFoundExceptionModel.builder().guildId(guildId).build();
this.model = GuildNotFoundExceptionModel
.builder()
.guildId(guildId)
.build();
}
@Override

View File

@@ -1,20 +0,0 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.templating.Templatable;
public class MemberNotFoundException extends AbstractoRunTimeException implements Templatable {
public MemberNotFoundException() {
super("Member was not found");
}
@Override
public String getTemplateName() {
return "member_not_found_exception";
}
@Override
public Object getTemplateModel() {
return new Object();
}
}

View File

@@ -9,7 +9,10 @@ public class PostTargetNotFoundException extends AbstractoRunTimeException imple
public PostTargetNotFoundException(String key) {
super("Post target not found");
this.model = PostTargetNotFoundExceptionModel.builder().postTargetKey(key).build();
this.model = PostTargetNotFoundExceptionModel
.builder()
.postTargetKey(key)
.build();
}
@Override

Some files were not shown because too many files have changed in this diff Show More