diff --git a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailThreadChannelNotFound.java b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailThreadChannelNotFound.java index 2e5ba8ffd..0199b2060 100644 --- a/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailThreadChannelNotFound.java +++ b/abstracto-application/abstracto-modules/modmail/modmail-int/src/main/java/dev/sheldan/abstracto/modmail/exception/ModMailThreadChannelNotFound.java @@ -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."); + } } diff --git a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckAsyncChannelGroupDeletedListener.java b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckChannelGroupDeletedListener.java similarity index 87% rename from abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckAsyncChannelGroupDeletedListener.java rename to abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckChannelGroupDeletedListener.java index 708460a90..48b55d978 100644 --- a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckAsyncChannelGroupDeletedListener.java +++ b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/main/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckChannelGroupDeletedListener.java @@ -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; diff --git a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckAsyncChannelGroupDeletedListenerTest.java b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckChannelGroupDeletedListenerTest.java similarity index 95% rename from abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckAsyncChannelGroupDeletedListenerTest.java rename to abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckChannelGroupDeletedListenerTest.java index ff02d8c88..ed91a9f32 100644 --- a/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckAsyncChannelGroupDeletedListenerTest.java +++ b/abstracto-application/abstracto-modules/repost-detection/repost-detection-impl/src/test/java/dev/sheldan/abstracto/repostdetection/listener/RepostCheckChannelGroupDeletedListenerTest.java @@ -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; diff --git a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emote/exception/TrackedEmoteNotFoundException.java b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emote/exception/TrackedEmoteNotFoundException.java index f3a47de3f..f68ed7ac2 100644 --- a/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emote/exception/TrackedEmoteNotFoundException.java +++ b/abstracto-application/abstracto-modules/statistic/statistic-int/src/main/java/dev/sheldan/abstracto/statistic/emote/exception/TrackedEmoteNotFoundException.java @@ -14,6 +14,7 @@ public class TrackedEmoteNotFoundException extends AbstractoRunTimeException imp } public TrackedEmoteNotFoundException() { + super("Tracked emote not found."); } @Override diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/urban/exception/NoUrbanDefinitionFoundException.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/urban/exception/NoUrbanDefinitionFoundException.java index d62a676ab..787c74ccf 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/urban/exception/NoUrbanDefinitionFoundException.java +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/urban/exception/NoUrbanDefinitionFoundException.java @@ -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"; diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/youtube/exception/YoutubeAPIException.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/youtube/exception/YoutubeAPIException.java index dcc4e4c07..ec4335fa5 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/youtube/exception/YoutubeAPIException.java +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/youtube/exception/YoutubeAPIException.java @@ -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) diff --git a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/youtube/exception/YoutubeVideoNotFoundException.java b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/youtube/exception/YoutubeVideoNotFoundException.java index a62515294..59f21f1a7 100644 --- a/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/youtube/exception/YoutubeVideoNotFoundException.java +++ b/abstracto-application/abstracto-modules/webservices/webservices-int/src/main/java/dev/sheldan/abstracto/webservices/youtube/exception/YoutubeVideoNotFoundException.java @@ -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"; diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java index 44105baf0..e618e4a4c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImpl.java @@ -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 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> listTask = context.getGuild().retrieveMembersByPrefix(inputString, 1); + CompletableFuture 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; } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/CoolDownPostExecution.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/CoolDownPostExecution.java new file mode 100644 index 000000000..dcd8531f6 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/post/CoolDownPostExecution.java @@ -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); + } + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/ChannelGroupCommandRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/ChannelGroupCommandRepository.java index 81df1d1af..1934dc336 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/ChannelGroupCommandRepository.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/ChannelGroupCommandRepository.java @@ -11,6 +11,8 @@ import java.util.Optional; public interface ChannelGroupCommandRepository extends JpaRepository { Optional findByCommandAndGroup(ACommand command, AChannelGroup group); + List findByCommandAndGroupIn(ACommand command, List groups); List findByCommand(ACommand command); + List findByCommandAndGroup_ChannelGroupType_GroupTypeKey(ACommand command, String groupType); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/CommandDisabledChannelGroupRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/CommandDisabledChannelGroupRepository.java new file mode 100644 index 000000000..4cb7096f5 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/CommandDisabledChannelGroupRepository.java @@ -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 { +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/CoolDownChannelGroupRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/CoolDownChannelGroupRepository.java new file mode 100644 index 000000000..c100d88c8 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/repository/CoolDownChannelGroupRepository.java @@ -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 { +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBean.java index 55b3d45cb..7ba3a3241 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBean.java @@ -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 allChannelGroupsOfCommand = channelGroupCommandService.getAllGroupCommandsForCommand(command); + List allChannelGroupsOfCommand = + channelGroupCommandService.getAllGroupCommandsForCommandWithType(command, COMMAND_CHANNEL_GROUP_KEY); for (AChannelGroupCommand aChannelGroupCommand : allChannelGroupsOfCommand) { + if(!aChannelGroupCommand.getGroup().getEnabled()) { + continue; + } Optional 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; } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownRuntimeStorage.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownRuntimeStorage.java new file mode 100644 index 000000000..6f1b62e3c --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownRuntimeStorage.java @@ -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 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> channelGroupCoolDowns = new HashMap<>(); + // maps server ID to member ID to command name to time at which the command can be executed again + private Map> memberCoolDowns = new HashMap<>(); +} + +@Getter +@Setter +@Builder +class CommandReUseMap { + private Map reUseTimes; +} \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownServiceBean.java new file mode 100644 index 000000000..a2c577dc4 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownServiceBean.java @@ -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 serverMap = storage.getChannelGroupCoolDowns().get(serverId); + if(!serverMap.keySet().isEmpty()) { + Long channelId = context.getChannel().getIdLong(); + AChannel channel = channelManagementService.loadChannel(channelId); + List 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 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 channelGroups = channelGroupService.getChannelGroupsOfChannelWithType(channel, COOL_DOWN_CHANNEL_GROUP_TYPE); + List 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 channelGroups = channelGroupService.getChannelGroupsOfChannelWithType(channel, COOL_DOWN_CHANNEL_GROUP_TYPE); + List 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 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> serverChannelGroupCoolDowns = storage.getChannelGroupCoolDowns(); + Map 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 channelGroups = channelGroupService.getChannelGroupsOfChannelWithType(channel, COOL_DOWN_CHANNEL_GROUP_TYPE); + List 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 reuseMapMap, Long mapId) { + if (reuseMapMap.containsKey(mapId)) { + Map 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> serverMemberCoolDowns = storage.getMemberCoolDowns(); + Map 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 reUseTimes = new HashMap<>(); + reUseTimes.put(commandName, newExecutionPoint); + return CommandReUseMap.builder().reUseTimes(reUseTimes).build(); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandDisabledServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandDisabledServiceBean.java new file mode 100644 index 000000000..dde55b698 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandDisabledServiceBean.java @@ -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); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/ChannelGroupCommandManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/ChannelGroupCommandManagementServiceBean.java index 90b1c5bc3..591d2a430 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/ChannelGroupCommandManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/ChannelGroupCommandManagementServiceBean.java @@ -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 groupCommandOptional = groupCommandRepository.findByCommandAndGroup(command, group); + if(!groupCommandOptional.isPresent()) { + createCommandInGroup(command, group); + } + } + + @Override + public void removeCommandFromGroup(ACommand command, AChannelGroup group) { + Optional 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 getAllGroupCommandsForCommandInGroups(ACommand command, List groups) { + return groupCommandRepository.findByCommandAndGroupIn(command, groups); + } + + @Override + public List getAllGroupCommandsForCommandWithType(ACommand command, String channelGroupType) { + return groupCommandRepository.findByCommandAndGroup_ChannelGroupType_GroupTypeKey(command, channelGroupType); + } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CommandDisabledChannelGroupManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CommandDisabledChannelGroupManagementServiceBean.java new file mode 100644 index 000000000..cc706416a --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CommandDisabledChannelGroupManagementServiceBean.java @@ -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()); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CommandInServerManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CommandInServerManagementServiceBean.java index fd57045d7..5bd7f6860 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CommandInServerManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CommandInServerManagementServiceBean.java @@ -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); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CoolDownChannelGroupManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CoolDownChannelGroupManagementServiceBean.java new file mode 100644 index 000000000..3f5944fbc --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/management/CoolDownChannelGroupManagementServiceBean.java @@ -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())); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/AddCommandToChannelGroup.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/AddCommandToChannelGroup.java new file mode 100644 index 000000000..fea639246 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/AddCommandToChannelGroup.java @@ -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 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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/DisableChannelGroup.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/DisableChannelGroup.java new file mode 100644 index 000000000..64c5f4771 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/DisableChannelGroup.java @@ -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 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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/DisableCommand.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/DisableCommand.java index b496d3808..56a1dd90f 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/DisableCommand.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/DisableCommand.java @@ -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 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 parameters = Arrays.asList(commandName, channelGroupName); HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build(); return CommandConfiguration.builder() .name("disableCommand") diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/EnableChannelGroup.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/EnableChannelGroup.java new file mode 100644 index 000000000..600efbe77 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/EnableChannelGroup.java @@ -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 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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/EnableCommand.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/EnableCommand.java index db9c98e46..2d1ffdb29 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/EnableCommand.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/EnableCommand.java @@ -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 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 parameters = Arrays.asList(commandName, channelGroupname); HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build(); return CommandConfiguration.builder() .name("enableCommand") diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/ListChannelGroups.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/ListChannelGroups.java index a0f0b2c83..46669a622 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/ListChannelGroups.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/ListChannelGroups.java @@ -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 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 convertAChannelGroupToChannelGroupChannel(List channelGroups) { - List converted = new ArrayList<>(); - channelGroups.forEach(group -> { - List convertedChannels = new ArrayList<>(); - group.getChannels().forEach(channel -> { - Optional 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 aliases = Arrays.asList("lsChGrp"); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/RemoveCommandFromChannelGroup.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/RemoveCommandFromChannelGroup.java new file mode 100644 index 000000000..8cec17163 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/channels/RemoveCommandFromChannelGroup.java @@ -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 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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/cooldown/ClearCommandCoolDowns.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/cooldown/ClearCommandCoolDowns.java new file mode 100644 index 000000000..aa327c428 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/cooldown/ClearCommandCoolDowns.java @@ -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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/cooldown/CommandCoolDownChannelGroup.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/cooldown/CommandCoolDownChannelGroup.java new file mode 100644 index 000000000..1072819be --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/cooldown/CommandCoolDownChannelGroup.java @@ -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 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 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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/cooldown/CommandCoolDownServer.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/cooldown/CommandCoolDownServer.java new file mode 100644 index 000000000..4f117b9db --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/config/cooldown/CommandCoolDownServer.java @@ -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 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 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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/help/Help.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/help/Help.java index 0e6110011..34308dcac 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/help/Help.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/commands/help/Help.java @@ -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 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 displayHelpOverview(CommandContext commandContext) { log.debug("Displaying help overview response."); ModuleDefinition moduleDefinition = moduleService.getDefaultModule(); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/ListenerExecutorConfig.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/ListenerExecutorConfig.java index 72e3978f7..7800c145d 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/ListenerExecutorConfig.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/config/ListenerExecutorConfig.java @@ -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"); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/AsyncCommandDisabledChannelGroupCreatedListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/AsyncCommandDisabledChannelGroupCreatedListener.java new file mode 100644 index 000000000..01f928088 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/AsyncCommandDisabledChannelGroupCreatedListener.java @@ -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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/AsyncCoolDownChannelGroupCreatedListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/AsyncCoolDownChannelGroupCreatedListener.java new file mode 100644 index 000000000..b0387130b --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/AsyncCoolDownChannelGroupCreatedListener.java @@ -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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/CommandDisabledChannelGroupDeletedListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/CommandDisabledChannelGroupDeletedListener.java new file mode 100644 index 000000000..b5b3b5e98 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/CommandDisabledChannelGroupDeletedListener.java @@ -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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/CoolDownChannelGroupDeletedListener.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/CoolDownChannelGroupDeletedListener.java new file mode 100644 index 000000000..0edb6a396 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/CoolDownChannelGroupDeletedListener.java @@ -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; + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncChannelGroupDeletedListenerManager.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncChannelGroupDeletedListenerManager.java deleted file mode 100644 index 106d52cf9..000000000 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/async/entity/AsyncChannelGroupDeletedListenerManager.java +++ /dev/null @@ -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 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) - ); - } - -} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/entity/SyncChannelGroupDeletedListenerManager.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/entity/SyncChannelGroupDeletedListenerManager.java new file mode 100644 index 000000000..3822effb5 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/listener/sync/entity/SyncChannelGroupDeletedListenerManager.java @@ -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 listener; + + @Autowired + private ListenerService listenerService; + + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void executeListener(ChannelGroupDeletedListenerModel model){ + listener.forEach(channelGroupCreatedListener -> + listenerService.executeListener(channelGroupCreatedListener, model) + ); + } + +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/provider/CoolDownChannelGroupInformationProviderBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/provider/CoolDownChannelGroupInformationProviderBean.java new file mode 100644 index 000000000..e254a5e28 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/provider/CoolDownChannelGroupInformationProviderBean.java @@ -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(); + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/ChannelGroupRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/ChannelGroupRepository.java index e8d733e08..4a6b99c4c 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/ChannelGroupRepository.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/ChannelGroupRepository.java @@ -12,7 +12,7 @@ import java.util.Optional; @Repository public interface ChannelGroupRepository extends JpaRepository { - Optional findByGroupNameAndServer(String name, AServer server); + Optional findByGroupNameIgnoreCaseAndServer(String name, AServer server); Optional findByGroupNameAndServerAndChannelGroupType_GroupTypeKey(String name, AServer server, String groupTyeKey); @@ -20,7 +20,7 @@ public interface ChannelGroupRepository extends JpaRepository findByServer(AServer server); - boolean existsByGroupNameAndServer(String name, AServer server); + boolean existsByGroupNameIgnoreCaseAndServer(String name, AServer server); List findAllByChannels(AChannel channel); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/ChannelGroupTypeRepository.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/ChannelGroupTypeRepository.java index 1fe304c6c..031b1f1fe 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/ChannelGroupTypeRepository.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/repository/ChannelGroupTypeRepository.java @@ -8,5 +8,5 @@ import java.util.Optional; @Repository public interface ChannelGroupTypeRepository extends JpaRepository { - Optional findByGroupTypeKey(String key); + Optional findByGroupTypeKeyIgnoreCase(String key); } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java index 212d37ee9..136648067 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupServiceBean.java @@ -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 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 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 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 convertAChannelGroupToChannelGroupChannel(List channelGroups) { + List converted = new ArrayList<>(); + channelGroups.forEach(group -> { + List convertedChannels = new ArrayList<>(); + group.getChannels().forEach(channel -> { + Optional 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; + } } diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelGroupManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelGroupManagementServiceBean.java index af2c260af..e8428e9f5 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelGroupManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelGroupManagementServiceBean.java @@ -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 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 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 channelGroupNames = extractChannelGroupNames(findAllInServerWithType(server.getId(), expectedType)); diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelGroupTypeManagementServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelGroupTypeManagementServiceBean.java index 2979845eb..5c5545bdb 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelGroupTypeManagementServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/service/management/ChannelGroupTypeManagementServiceBean.java @@ -18,7 +18,7 @@ public class ChannelGroupTypeManagementServiceBean implements ChannelGroupTypeMa @Override public Optional findChannelGroupTypeByKeyOptional(String key) { - return repository.findByGroupTypeKey(key); + return repository.findByGroupTypeKeyIgnoreCase(key); } @Override diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2-core/collection.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.0-core/collection.xml similarity index 100% rename from abstracto-application/core/core-impl/src/main/resources/migrations/1.2-core/collection.xml rename to abstracto-application/core/core-impl/src/main/resources/migrations/1.2.0-core/collection.xml diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2-core/core-seedData/channelGroupType.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.0-core/core-seedData/channelGroupType.xml similarity index 100% rename from abstracto-application/core/core-impl/src/main/resources/migrations/1.2-core/core-seedData/channelGroupType.xml rename to abstracto-application/core/core-impl/src/main/resources/migrations/1.2.0-core/core-seedData/channelGroupType.xml diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2-core/core-seedData/data.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.0-core/core-seedData/data.xml similarity index 100% rename from abstracto-application/core/core-impl/src/main/resources/migrations/1.2-core/core-seedData/data.xml rename to abstracto-application/core/core-impl/src/main/resources/migrations/1.2.0-core/core-seedData/data.xml diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/collection.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/collection.xml new file mode 100644 index 000000000..64bad270f --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/collection.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/channel_group_type.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/channel_group_type.xml new file mode 100644 index 000000000..2288adb74 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/channel_group_type.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/command.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/command.xml new file mode 100644 index 000000000..7ea7e5759 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/command.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/data.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/data.xml new file mode 100644 index 000000000..a5d988ec2 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/data.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/channel_group.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/channel_group.xml new file mode 100644 index 000000000..3d9ddd09f --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/channel_group.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/channel_group_type.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/channel_group_type.xml new file mode 100644 index 000000000..8c4b06c16 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/channel_group_type.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/command_disabled_channel_group.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/command_disabled_channel_group.xml new file mode 100644 index 000000000..88665c02d --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/command_disabled_channel_group.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + 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(); + + + 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(); + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/command_in_server.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/command_in_server.xml new file mode 100644 index 000000000..9e98c1641 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/command_in_server.xml @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/cool_down_channel_group.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/cool_down_channel_group.xml new file mode 100644 index 000000000..0ee676170 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/cool_down_channel_group.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + 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(); + + + 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(); + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/tables.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/tables.xml new file mode 100644 index 000000000..2c6d1ecc9 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-tables/tables.xml @@ -0,0 +1,14 @@ + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/core-changeLog.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/core-changeLog.xml index 63bcae2fd..d3671cf68 100644 --- a/abstracto-application/core/core-impl/src/main/resources/migrations/core-changeLog.xml +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/core-changeLog.xml @@ -9,8 +9,9 @@ - + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java index 023812a5f..51dd017cd 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/handler/MemberParameterHandlerImplTest.java @@ -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 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 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 future = testUnit.handleAsync(getPieceWithValue(input), null, parameter, message, command); Member returnedMember = (Member) future.join(); Assert.assertFalse(future.isCompletedExceptionally()); diff --git a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBeanTest.java b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBeanTest.java index 46345ecd8..963a48936 100644 --- a/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBeanTest.java +++ b/abstracto-application/core/core-impl/src/test/java/dev/sheldan/abstracto/core/command/service/ChannelGroupCommandServiceBeanTest.java @@ -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); diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/AbstractConditionableCommand.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/AbstractConditionableCommand.java index 298701d8d..b2dced618 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/AbstractConditionableCommand.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/AbstractConditionableCommand.java @@ -32,10 +32,14 @@ public abstract class AbstractConditionableCommand implements ConditionalCommand @Autowired private AdminModeCondition adminModeCondition; + @Autowired + private CommandCoolDownCondition coolDownCondition; + @Override public List 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) { diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/CommandCoolDownCondition.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/CommandCoolDownCondition.java new file mode 100644 index 000000000..c3034c066 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/CommandCoolDownCondition.java @@ -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(); + } + } +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/detail/CommandCoolDownDetail.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/detail/CommandCoolDownDetail.java new file mode 100644 index 000000000..44624b48d --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/condition/detail/CommandCoolDownDetail.java @@ -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; + } +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfiguration.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfiguration.java index 10a12d304..fa4d75731 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfiguration.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/config/CommandConfiguration.java @@ -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(); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/config/CommandCoolDownConfig.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/config/CommandCoolDownConfig.java new file mode 100644 index 000000000..2c4734fbe --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/config/CommandCoolDownConfig.java @@ -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; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/ChannelGroupIncorrectTypeException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/ChannelGroupIncorrectTypeException.java index 6f0bbecb0..97e53ecff 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/ChannelGroupIncorrectTypeException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/ChannelGroupIncorrectTypeException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasAlreadyExistsException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasAlreadyExistsException.java index c23a3f52a..04cfb685c 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasAlreadyExistsException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasAlreadyExistsException.java @@ -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) diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasDoesNotExistsException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasDoesNotExistsException.java index 6fde278b1..986b3e001 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasDoesNotExistsException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasDoesNotExistsException.java @@ -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"; diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasHidesCommandException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasHidesCommandException.java index 988ca3266..bc8a7b502 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasHidesCommandException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandAliasHidesCommandException.java @@ -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) diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandNotFoundInGroupException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandNotFoundInGroupException.java new file mode 100644 index 000000000..36067d13e --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandNotFoundInGroupException.java @@ -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(); + } +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandParameterValidationException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandParameterValidationException.java index eb5ec015f..59d2b04c6 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandParameterValidationException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/CommandParameterValidationException.java @@ -17,6 +17,7 @@ public class CommandParameterValidationException extends AbstractoRunTimeExcepti private final CommandParameterValidationExceptionModel model; public CommandParameterValidationException(List validatorParams, String template, Parameter parameter) { + super("Command parameter failed to validate."); this.model = CommandParameterValidationExceptionModel .builder() .validationTemplate(template) diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/IncorrectFeatureModeException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/IncorrectFeatureModeException.java index e1ddfb827..93477a7e5 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/IncorrectFeatureModeException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/IncorrectFeatureModeException.java @@ -12,7 +12,12 @@ public class IncorrectFeatureModeException extends AbstractoRunTimeException imp private final IncorrectFeatureModeModel model; public IncorrectFeatureModeException(FeatureDefinition featureDefinition, List requiredModes) { - this.model = IncorrectFeatureModeModel.builder().featureDefinition(featureDefinition).requiredModes(requiredModes).build(); + super("Incorrect feature mode."); + this.model = IncorrectFeatureModeModel + .builder() + .featureDefinition(featureDefinition) + .requiredModes(requiredModes) + .build(); } @Override diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/IncorrectParameterException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/IncorrectParameterException.java index b96648959..8b4352955 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/IncorrectParameterException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/exception/IncorrectParameterException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/execution/CoolDownCheckResult.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/execution/CoolDownCheckResult.java new file mode 100644 index 000000000..e4fbce049 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/execution/CoolDownCheckResult.java @@ -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 +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/condition/CommandCoolDownDetailModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/condition/CommandCoolDownDetailModel.java new file mode 100644 index 000000000..13f2e6898 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/condition/CommandCoolDownDetailModel.java @@ -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; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/ACommandInAServer.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/ACommandInAServer.java index 67e9cb3e9..4027cef4e 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/ACommandInAServer.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/ACommandInAServer.java @@ -61,6 +61,9 @@ public class ACommandInAServer implements Serializable { @Column(name = "updated") private Instant updated; + @Column(name = "cool_down") + private Long coolDown; + } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/CommandDisabledChannelGroup.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/CommandDisabledChannelGroup.java new file mode 100644 index 000000000..96d907aec --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/CommandDisabledChannelGroup.java @@ -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; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/CoolDownChannelGroup.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/CoolDownChannelGroup.java new file mode 100644 index 000000000..6bd25b29e --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/model/database/CoolDownChannelGroup.java @@ -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; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownService.java new file mode 100644 index 000000000..6605ba779 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownService.java @@ -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); +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/CommandDisabledService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/CommandDisabledService.java new file mode 100644 index 000000000..7133d74b2 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/CommandDisabledService.java @@ -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); +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/management/ChannelGroupCommandManagementService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/management/ChannelGroupCommandManagementService.java index 0d5d65559..bfbba0a3d 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/management/ChannelGroupCommandManagementService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/command/service/management/ChannelGroupCommandManagementService.java @@ -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 getAllGroupCommandsForCommand(ACommand command); + List getAllGroupCommandsForCommandInGroups(ACommand command, List groups); + List getAllGroupCommandsForCommandWithType(ACommand command, String channelGroupType); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/CategoryNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/CategoryNotFoundException.java index 1cc478cc9..b87b52872 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/CategoryNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/CategoryNotFoundException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelGroupTypeNotFound.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelGroupTypeNotFound.java index b6ecda555..7a4e09e9c 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelGroupTypeNotFound.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelGroupTypeNotFound.java @@ -10,7 +10,11 @@ public class ChannelGroupTypeNotFound extends AbstractoRunTimeException implemen private final ChannelGroupTypeNotFoundExceptionModel model; public ChannelGroupTypeNotFound(List channelGroupTypeKeys) { - this.model = ChannelGroupTypeNotFoundExceptionModel.builder().availableGroupTypeKeys(channelGroupTypeKeys).build(); + super("Channel group type not found."); + this.model = ChannelGroupTypeNotFoundExceptionModel + .builder() + .availableGroupTypeKeys(channelGroupTypeKeys) + .build(); } @Override diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelInMultipleChannelGroupsException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelInMultipleChannelGroupsException.java new file mode 100644 index 000000000..8d2510279 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelInMultipleChannelGroupsException.java @@ -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; + } +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotFoundException.java index ce126c6d3..cd3d796df 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotFoundException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotInGuildException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotInGuildException.java index 799de017b..7a34430e4 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotInGuildException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ChannelNotInGuildException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/CommandInMultipleChannelGroupsException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/CommandInMultipleChannelGroupsException.java new file mode 100644 index 000000000..7c237dd4e --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/CommandInMultipleChannelGroupsException.java @@ -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; + } +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ConfigurationKeyNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ConfigurationKeyNotFoundException.java index 5a0fce52d..44c7b5c40 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ConfigurationKeyNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ConfigurationKeyNotFoundException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ConfiguredEmoteNotUsableException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ConfiguredEmoteNotUsableException.java index 9bd2ecc04..5bc5efc4b 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ConfiguredEmoteNotUsableException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ConfiguredEmoteNotUsableException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/DurationFormatException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/DurationFormatException.java index 758f89eac..2cc9ed4ea 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/DurationFormatException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/DurationFormatException.java @@ -12,7 +12,11 @@ public class DurationFormatException extends AbstractoRunTimeException implement public DurationFormatException(String wrongFormat, List validFormats) { super("Duration format exception "); - this.model = DurationFormatExceptionModel.builder().invalidFormat(wrongFormat).validFormats(validFormats).build(); + this.model = DurationFormatExceptionModel + .builder() + .invalidFormat(wrongFormat) + .validFormats(validFormats) + .build(); } @Override diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotDefinedException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotDefinedException.java index e69afa7ab..7a154b7a5 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotDefinedException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotDefinedException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundException.java index f02368ff5..bf130de1b 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundException.java @@ -11,7 +11,11 @@ public class EmoteNotFoundException extends AbstractoRunTimeException implements public EmoteNotFoundException(String key, List availableEmotes) { super("Emote not found"); - this.model = EmoteNotFoundExceptionModel.builder().emoteKey(key).available(availableEmotes).build(); + this.model = EmoteNotFoundExceptionModel + .builder() + .emoteKey(key) + .available(availableEmotes) + .build(); } @Override diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundInDbException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundInDbException.java index b99ff2c1e..11b4865c2 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundInDbException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotFoundInDbException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotInServerException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotInServerException.java index 91ba3b6d3..d40699965 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotInServerException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotInServerException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotUsableException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotUsableException.java index aeb1da5d5..5fc0375b6 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotUsableException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/EmoteNotUsableException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/FeatureModeNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/FeatureModeNotFoundException.java index 0ad3af4bd..5e41d7f69 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/FeatureModeNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/FeatureModeNotFoundException.java @@ -11,7 +11,11 @@ public class FeatureModeNotFoundException extends AbstractoRunTimeException impl public FeatureModeNotFoundException(String featureMode, List 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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/FeatureNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/FeatureNotFoundException.java index aaa885936..a15208cd0 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/FeatureNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/FeatureNotFoundException.java @@ -11,8 +11,11 @@ public class FeatureNotFoundException extends AbstractoRunTimeException implemen public FeatureNotFoundException(String feature, List availableFeatures) { super("Feature not found."); - this.model = FeatureNotFoundExceptionModel.builder().featureName(feature).availableFeatures(availableFeatures).build(); - + this.model = FeatureNotFoundExceptionModel + .builder() + .featureName(feature) + .availableFeatures(availableFeatures) + .build(); } @Override diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/GuildNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/GuildNotFoundException.java index 9e8cdab90..54831424f 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/GuildNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/GuildNotFoundException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/MemberNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/MemberNotFoundException.java deleted file mode 100644 index 71644ccc7..000000000 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/MemberNotFoundException.java +++ /dev/null @@ -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(); - } -} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/PostTargetNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/PostTargetNotFoundException.java index 6719a446d..dba821164 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/PostTargetNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/PostTargetNotFoundException.java @@ -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 diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/PostTargetNotValidException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/PostTargetNotValidException.java index cb5cc1beb..c9c945f6a 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/PostTargetNotValidException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/PostTargetNotValidException.java @@ -11,7 +11,11 @@ public class PostTargetNotValidException extends AbstractoRunTimeException imple public PostTargetNotValidException(String key, List available) { super("Given post target was not in the list of valid post targets"); - this.model = PostTargetNotValidExceptionModel.builder().availableTargets(available).postTargetKey(key).build(); + this.model = PostTargetNotValidExceptionModel + .builder() + .availableTargets(available) + .postTargetKey(key) + .build(); } @Override diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityGroupExistsException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityGroupExistsException.java index 3ad732610..3449dce78 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityGroupExistsException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityGroupExistsException.java @@ -3,6 +3,11 @@ package dev.sheldan.abstracto.core.exception; import dev.sheldan.abstracto.core.templating.Templatable; public class ProfanityGroupExistsException extends AbstractoRunTimeException implements Templatable { + + public ProfanityGroupExistsException() { + super("Profanity group already exists."); + } + @Override public String getTemplateName() { return "profanity_group_exists_exception"; diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityGroupNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityGroupNotFoundException.java index 2aca16c57..86834864a 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityGroupNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityGroupNotFoundException.java @@ -3,6 +3,11 @@ package dev.sheldan.abstracto.core.exception; import dev.sheldan.abstracto.core.templating.Templatable; public class ProfanityGroupNotFoundException extends AbstractoRunTimeException implements Templatable { + + public ProfanityGroupNotFoundException() { + super("Profanity group not found."); + } + @Override public String getTemplateName() { return "profanity_group_not_found_exception"; diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityRegexExistsException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityRegexExistsException.java index 68afaa902..7a83474ca 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityRegexExistsException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityRegexExistsException.java @@ -3,6 +3,11 @@ package dev.sheldan.abstracto.core.exception; import dev.sheldan.abstracto.core.templating.Templatable; public class ProfanityRegexExistsException extends AbstractoRunTimeException implements Templatable { + + public ProfanityRegexExistsException() { + super("Profanity regex already exists."); + } + @Override public String getTemplateName() { return "profanity_regex_exists_exception"; diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityRegexNotFoundException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityRegexNotFoundException.java index ddff26e4a..d11807290 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityRegexNotFoundException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/ProfanityRegexNotFoundException.java @@ -3,6 +3,11 @@ package dev.sheldan.abstracto.core.exception; import dev.sheldan.abstracto.core.templating.Templatable; public class ProfanityRegexNotFoundException extends AbstractoRunTimeException implements Templatable { + + public ProfanityRegexNotFoundException() { + super("Profanity regex not found."); + } + @Override public String getTemplateName() { return "profanity_regex_not_found_exception"; diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/UnknownMentionTypeException.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/UnknownMentionTypeException.java index 58f23d93a..46b29f77b 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/UnknownMentionTypeException.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/exception/UnknownMentionTypeException.java @@ -3,6 +3,11 @@ package dev.sheldan.abstracto.core.exception; import dev.sheldan.abstracto.core.templating.Templatable; public class UnknownMentionTypeException extends AbstractoRunTimeException implements Templatable { + + public UnknownMentionTypeException() { + super("Unknown mention type"); + } + @Override public String getTemplateName() { return "unknown_mention_type_exception"; diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/sync/entity/AsyncChannelGroupDeletedListener.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/sync/entity/ChannelGroupDeletedListener.java similarity index 66% rename from abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/sync/entity/AsyncChannelGroupDeletedListener.java rename to abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/sync/entity/ChannelGroupDeletedListener.java index 3751e13ec..f68716945 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/sync/entity/AsyncChannelGroupDeletedListener.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/listener/sync/entity/ChannelGroupDeletedListener.java @@ -4,5 +4,5 @@ import dev.sheldan.abstracto.core.listener.AbstractoListener; import dev.sheldan.abstracto.core.listener.DefaultListenerResult; import dev.sheldan.abstracto.core.models.listener.ChannelGroupDeletedListenerModel; -public interface AsyncChannelGroupDeletedListener extends AbstractoListener { +public interface ChannelGroupDeletedListener extends AbstractoListener { } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/AServerChannelUserId.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/AServerChannelUserId.java index d40cf57b6..e4beed758 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/AServerChannelUserId.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/AServerChannelUserId.java @@ -11,4 +11,12 @@ public class AServerChannelUserId { private Long guildId; private Long channelId; private Long userId; + + public ServerIdChannelId toServerChannelId() { + return ServerIdChannelId. + builder() + .serverId(guildId) + .channelId(channelId) + .build(); + } } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/ServerIdChannelId.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/ServerIdChannelId.java new file mode 100644 index 000000000..f7a54ad51 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/ServerIdChannelId.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.core.models; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class ServerIdChannelId { + private Long serverId; + private Long channelId; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelGroup.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelGroup.java index 31eae7f6d..0fd713186 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelGroup.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/AChannelGroup.java @@ -33,7 +33,7 @@ public class AChannelGroup implements Serializable { @JoinColumn(name = "group_type_id") private ChannelGroupType channelGroupType; - @OneToMany(mappedBy = "group", fetch = FetchType.LAZY) + @OneToMany(mappedBy = "group", fetch = FetchType.LAZY, orphanRemoval = true) private List channelGroupCommands; @Column(name = "created") @@ -49,5 +49,8 @@ public class AChannelGroup implements Serializable { inverseJoinColumns = @JoinColumn(name = "channel_id")) private List channels; + @Column(name = "enabled") + private Boolean enabled; + } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/ChannelGroupType.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/ChannelGroupType.java index b21b0a892..911c0a523 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/ChannelGroupType.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/database/ChannelGroupType.java @@ -28,4 +28,10 @@ public class ChannelGroupType { @Column(name = "updated") private Instant updated; + + @Column(name = "allows_channel_in_multiple") + private Boolean allowsChannelsInMultiple; + + @Column(name = "allows_commands_in_multiple") + private Boolean allowsCommandsInMultiple; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/exception/ChannelInMultipleChannelGroupsExceptionModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/exception/ChannelInMultipleChannelGroupsExceptionModel.java new file mode 100644 index 000000000..32a99e693 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/exception/ChannelInMultipleChannelGroupsExceptionModel.java @@ -0,0 +1,12 @@ +package dev.sheldan.abstracto.core.models.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class ChannelInMultipleChannelGroupsExceptionModel { + private String channelGroupName; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/exception/CommandInMultipleChannelGroupsExceptionModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/exception/CommandInMultipleChannelGroupsExceptionModel.java new file mode 100644 index 000000000..b442f61e2 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/exception/CommandInMultipleChannelGroupsExceptionModel.java @@ -0,0 +1,12 @@ +package dev.sheldan.abstracto.core.models.exception; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class CommandInMultipleChannelGroupsExceptionModel { + private String channelGroupName; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/ChannelGroupInformation.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/ChannelGroupInformation.java new file mode 100644 index 000000000..47190b1dd --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/ChannelGroupInformation.java @@ -0,0 +1,4 @@ +package dev.sheldan.abstracto.core.models.provider; + +public interface ChannelGroupInformation extends ProviderInformation { +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/ChannelGroupInformationRequest.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/ChannelGroupInformationRequest.java new file mode 100644 index 000000000..153f37e32 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/ChannelGroupInformationRequest.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.core.models.provider; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class ChannelGroupInformationRequest implements InformationRequest { + private Long channelGroupId; + private String channelGroupType; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/CoolDownChannelInformation.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/CoolDownChannelInformation.java new file mode 100644 index 000000000..383c5f1d3 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/CoolDownChannelInformation.java @@ -0,0 +1,30 @@ +package dev.sheldan.abstracto.core.models.provider; + +import dev.sheldan.abstracto.core.models.template.provider.CoolDownChannelInformationModel; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.time.Duration; + +@Setter +@Getter +@Builder +public class CoolDownChannelInformation implements ChannelGroupInformation { + private Long channelCoolDown; + private Long memberCoolDown; + + @Override + public String getTemplateName() { + return "channel_group_provider_cool_down_display"; + } + + @Override + public Object getTemplateModel() { + return CoolDownChannelInformationModel + .builder() + .channelCoolDown(Duration.ofSeconds(this.channelCoolDown)) + .memberCoolDown(Duration.ofSeconds(this.memberCoolDown)) + .build(); + } +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/InformationRequest.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/InformationRequest.java new file mode 100644 index 000000000..ab28f2049 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/InformationRequest.java @@ -0,0 +1,4 @@ +package dev.sheldan.abstracto.core.models.provider; + +public interface InformationRequest { +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/ProviderInformation.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/ProviderInformation.java new file mode 100644 index 000000000..cafed34a0 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/provider/ProviderInformation.java @@ -0,0 +1,6 @@ +package dev.sheldan.abstracto.core.models.provider; + +import dev.sheldan.abstracto.core.templating.Templatable; + +public interface ProviderInformation extends Templatable { +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/ChannelGroupModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/ChannelGroupModel.java index c819e238b..89d8d4c6d 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/ChannelGroupModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/ChannelGroupModel.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.core.models.template.commands; +import dev.sheldan.abstracto.core.models.provider.ChannelGroupInformation; import lombok.Builder; import lombok.Getter; import lombok.Setter; @@ -12,5 +13,7 @@ import java.util.List; public class ChannelGroupModel { private String name; private String typeKey; + private Boolean enabled; private List channels; + private ChannelGroupInformation channelGroupInformation; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/help/HelpCommandDetailsModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/help/HelpCommandDetailsModel.java index 8abe189fe..e10177756 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/help/HelpCommandDetailsModel.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/commands/help/HelpCommandDetailsModel.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.core.models.template.commands.help; import dev.sheldan.abstracto.core.command.config.CommandConfiguration; +import dev.sheldan.abstracto.core.command.config.CommandCoolDownConfig; import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext; import lombok.Getter; import lombok.Setter; @@ -19,4 +20,5 @@ public class HelpCommandDetailsModel extends UserInitiatedServerContext { private List allowedRoles; private List immuneRoles; private Boolean restricted; + private CommandCoolDownConfig cooldowns; } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/provider/CoolDownChannelInformationModel.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/provider/CoolDownChannelInformationModel.java new file mode 100644 index 000000000..a4b7a27ff --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/models/template/provider/CoolDownChannelInformationModel.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.core.models.template.provider; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.time.Duration; + +@Getter +@Setter +@Builder +public class CoolDownChannelInformationModel { + private Duration channelCoolDown; + private Duration memberCoolDown; +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/provider/ChannelGroupInformationProvider.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/provider/ChannelGroupInformationProvider.java new file mode 100644 index 000000000..cdfdc3e1c --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/provider/ChannelGroupInformationProvider.java @@ -0,0 +1,5 @@ +package dev.sheldan.abstracto.core.provider; + +public interface ChannelGroupInformationProvider extends InformationProvider { + +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/provider/InformationProvider.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/provider/InformationProvider.java new file mode 100644 index 000000000..518df5629 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/provider/InformationProvider.java @@ -0,0 +1,9 @@ +package dev.sheldan.abstracto.core.provider; + +import dev.sheldan.abstracto.core.models.provider.InformationRequest; +import dev.sheldan.abstracto.core.models.provider.ProviderInformation; + +public interface InformationProvider { + boolean handlesRequest(R informationRequest); + I retrieveInformation(R informationRequest); +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupService.java index 31d386734..687194f30 100644 --- a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupService.java +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/ChannelGroupService.java @@ -3,6 +3,7 @@ package dev.sheldan.abstracto.core.service; import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannelGroup; import dev.sheldan.abstracto.core.models.database.ChannelGroupType; +import dev.sheldan.abstracto.core.models.template.commands.ChannelGroupModel; import net.dv8tion.jda.api.entities.TextChannel; import java.util.List; @@ -16,8 +17,11 @@ public interface ChannelGroupService { void removeChannelFromChannelGroup(String channelGroupName, TextChannel textChannel); void removeChannelFromChannelGroup(String channelGroupName, Long channelId, Long serverId); void removeChannelFromChannelGroup(String channelGroupName, AChannel channel); - void disableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId); - void enableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId); + void addCommandToChannelGroup(String commandName, String channelGroupName, Long serverId); + void removeCommandFromChannelGroup(String commandName, String channelGroupName, Long serverId); + void disableChannelGroup(String channelGroupName, Long serverId); + void enableChannelGroup(String channelGroupName, Long serverId); boolean doesGroupExist(String groupName, Long serverId); List getChannelGroupsOfChannelWithType(AChannel channel, String groupTypeKey); + List convertAChannelGroupToChannelGroupChannel(List channelGroups); } diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/CommandDisabledChannelGroupManagementService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/CommandDisabledChannelGroupManagementService.java new file mode 100644 index 000000000..110621d09 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/CommandDisabledChannelGroupManagementService.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.core.service.management; + +import dev.sheldan.abstracto.core.command.model.database.CommandDisabledChannelGroup; +import dev.sheldan.abstracto.core.models.database.AChannelGroup; + +public interface CommandDisabledChannelGroupManagementService { + CommandDisabledChannelGroup createCommandDisabledChannelGroup(AChannelGroup channelGroup); + void deleteCommandDisabledChannelGroup(AChannelGroup channelGroup); + CommandDisabledChannelGroup findViaChannelGroup(AChannelGroup channelGroup); +} diff --git a/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/CoolDownChannelGroupManagementService.java b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/CoolDownChannelGroupManagementService.java new file mode 100644 index 000000000..99260d9d7 --- /dev/null +++ b/abstracto-application/core/core-int/src/main/java/dev/sheldan/abstracto/core/service/management/CoolDownChannelGroupManagementService.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.core.service.management; + +import dev.sheldan.abstracto.core.command.model.database.CoolDownChannelGroup; +import dev.sheldan.abstracto.core.models.database.AChannelGroup; + +public interface CoolDownChannelGroupManagementService { + CoolDownChannelGroup createCoolDownChannelGroup(AChannelGroup aChannelGroup); + CoolDownChannelGroup findByChannelGroupId(Long channelGroupId); + void deleteCoolDownChannelGroup(AChannelGroup aChannelGroup); +} diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/modules/core.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/modules/core.adoc index 7e3ab301e..808f2d972 100644 --- a/abstracto-application/documentation/src/main/docs/asciidoc/modules/core.adoc +++ b/abstracto-application/documentation/src/main/docs/asciidoc/modules/core.adoc @@ -167,7 +167,28 @@ Deleting a profanity group:: Showing the uptime of the bot:: * Usage: `uptime` * Shows the uptime and start time of the bot instance. - +Adding a command to a channel group:: +* Usage: `addCommandToChannelGroup ` +* Description: Adds the command `commandName` to the channel group `channelGroupName`. This can be used to add the command to a channel group which can disable the command or set a cooldown on the command. +Disabling a channel group:: +* Usage: `disableChannelGroup ` +* Description: Disables the effect the channel group `channelGroupName` has. +Enabling a channel group:: +* Usage: `enableChannelGroup ` +* Description: Enables the effect the channel group `channelGroupName` has. +Removing a command from a channel group:: +* Usage: `removeCommandFromChannelGroup ` +* Description: Removes the command `commandName` from the channel group `channelGroupName`. This can be used to remove the command from a channel group which can enable the command or remove a cooldown on the command. +Clearing cooldowns:: +* Usage: `clearCommandCoolDowns` +* Description: Resets all currently active cooldowns of the current server, so every command can be used again. +Setting channel and member cooldowns in a channel group:: +* Usage: `commandCoolDownChannelGroup ` +* Description: Sets the cooldown of the commands of the channel group `channelGroupName` to `channelDuration` for the channel group +and `memberDuration` for each member. +Setting the global cooldown for a command:: +* Usage: `commandCoolDownServer ` +* Description: Sets the cooldown for command `command` to `duration` for the whole server. .What does it mean if a role is immune? A command can take a member as a target, for example `ban`. If a role is considered immune, this means, if the member which is the target of the command has the given role, this command will fail. Not all commands support this feature, but only the following: @@ -188,4 +209,9 @@ If the feature mode is enabled, the messages from the thread are logged in the r .What is a profanity group? A profanity group is just a container for various regexes. They are grouped together in order to be identified together and kept organized. -Each profanity regex within that group has another identified. For example a regex group handles the word 'test'. Then a profanity regex is for all lower cases, this regex can be named 'lower', and the regex group is then named 'test'. \ No newline at end of file +Each profanity regex within that group has another identified. For example a regex group handles the word 'test'. Then a profanity regex is for all lower cases, this regex can be named 'lower', and the regex group is then named 'test'. + +.How do multiple cooldowns interact +If there are multiple cooldowns on a command active, the longest cooldown will decide the cool down. +A channel cannot be in multiple cool down channel groups and this is actively enforced by the command. +If a cooldown is active, an error message is shown with the duration after which the command can be used again. \ No newline at end of file