added command to manage channel groups

added ability to disable command in channel groups
refactored embed handling to support multiple embeds to be send at once (handling to decide to split into multiple embeds is still needed)
This commit is contained in:
Sheldan
2020-04-06 00:51:07 +02:00
parent 4b3765ee0f
commit 20cb43d071
60 changed files with 840 additions and 155 deletions

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.AbstractFeatureFlaggedCommand;
import dev.sheldan.abstracto.core.command.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.HelpInfo;
import dev.sheldan.abstracto.core.command.execution.*;
import dev.sheldan.abstracto.moderation.Moderation;
@@ -18,7 +18,7 @@ import java.util.List;
@Component
@Slf4j
public class Ban extends AbstractFeatureFlaggedCommand {
public class Ban extends AbstractConditionableCommand {
@Autowired
private BanService banService;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.AbstractFeatureFlaggedCommand;
import dev.sheldan.abstracto.core.command.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.HelpInfo;
import dev.sheldan.abstracto.core.command.execution.*;
import dev.sheldan.abstracto.moderation.Moderation;
@@ -15,7 +15,7 @@ import java.util.ArrayList;
import java.util.List;
@Component
public class BanId extends AbstractFeatureFlaggedCommand {
public class BanId extends AbstractConditionableCommand {
@Autowired
private TemplateService templateService;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.AbstractFeatureFlaggedCommand;
import dev.sheldan.abstracto.core.command.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.HelpInfo;
import dev.sheldan.abstracto.core.command.execution.*;
import dev.sheldan.abstracto.moderation.Moderation;
@@ -16,7 +16,7 @@ import java.util.ArrayList;
import java.util.List;
@Component
public class Kick extends AbstractFeatureFlaggedCommand {
public class Kick extends AbstractConditionableCommand {
@Autowired
private TemplateService templateService;

View File

@@ -5,7 +5,6 @@ import dev.sheldan.abstracto.core.command.execution.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.Parameter;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.service.Bot;
import dev.sheldan.abstracto.moderation.Moderation;
import dev.sheldan.abstracto.moderation.config.ModerationFeatures;
import dev.sheldan.abstracto.moderation.service.SlowModeService;
@@ -18,7 +17,7 @@ import java.util.ArrayList;
import java.util.List;
@Component
public class SlowMode extends AbstractFeatureFlaggedCommand {
public class SlowMode extends AbstractConditionableCommand {
@Autowired
private SlowModeService slowModeService;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.moderation.command;
import dev.sheldan.abstracto.core.command.AbstractFeatureFlaggedCommand;
import dev.sheldan.abstracto.core.command.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.HelpInfo;
import dev.sheldan.abstracto.core.command.execution.*;
import dev.sheldan.abstracto.core.service.management.UserManagementService;
@@ -19,7 +19,7 @@ import java.util.List;
@Component
@Slf4j
public class Warn extends AbstractFeatureFlaggedCommand {
public class Warn extends AbstractConditionableCommand {
@Autowired
private UserManagementService userManagementService;

View File

@@ -14,7 +14,7 @@ import java.util.ArrayList;
import java.util.List;
@Component
public class ShowEmote extends AbstractFeatureFlaggedCommand {
public class ShowEmote extends AbstractConditionableCommand {
private static final String SHOW_EMOTE_RESPONSE_TEMPLATE = "showEmote_response";

View File

@@ -1,12 +1,13 @@
package dev.sheldan.abstracto.utility.command;
import dev.sheldan.abstracto.core.command.AbstractFeatureFlaggedCommand;
import dev.sheldan.abstracto.core.command.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.HelpInfo;
import dev.sheldan.abstracto.core.command.execution.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.Parameter;
import dev.sheldan.abstracto.core.models.MessageToSend;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.templating.TemplateService;
import dev.sheldan.abstracto.utility.Utility;
import dev.sheldan.abstracto.utility.config.UtilityFeatures;
@@ -19,7 +20,7 @@ import java.util.ArrayList;
import java.util.List;
@Component
public class StarStats extends AbstractFeatureFlaggedCommand {
public class StarStats extends AbstractConditionableCommand {
public static final String STARSTATS_RESPONSE_TEMPLATE = "starStats_response";
@Autowired
@@ -28,11 +29,14 @@ public class StarStats extends AbstractFeatureFlaggedCommand {
@Autowired
private TemplateService templateService;
@Autowired
private ChannelService channelService;
@Override
public CommandResult execute(CommandContext commandContext) {
StarStatsModel result = starboardService.retrieveStarStats(commandContext.getGuild().getIdLong());
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARSTATS_RESPONSE_TEMPLATE, result);
commandContext.getChannel().sendMessage(messageToSend.getEmbed()).queue();
channelService.sendMessageToEndInTextChannel(messageToSend, commandContext.getChannel());
return CommandResult.fromSuccess();
}

View File

@@ -16,7 +16,7 @@ import java.util.ArrayList;
import java.util.List;
@Component
public class Remind extends AbstractFeatureFlaggedCommand {
public class Remind extends AbstractConditionableCommand {
@Autowired
private ReminderService remindService;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.utility.command.suggest;
import dev.sheldan.abstracto.core.command.AbstractFeatureFlaggedCommand;
import dev.sheldan.abstracto.core.command.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.HelpInfo;
import dev.sheldan.abstracto.core.command.execution.*;
import dev.sheldan.abstracto.utility.Utility;
@@ -14,7 +14,7 @@ import java.util.ArrayList;
import java.util.List;
@Component
public class Accept extends AbstractFeatureFlaggedCommand {
public class Accept extends AbstractConditionableCommand {
@Autowired
private SuggestionService suggestionService;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.utility.command.suggest;
import dev.sheldan.abstracto.core.command.AbstractFeatureFlaggedCommand;
import dev.sheldan.abstracto.core.command.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.HelpInfo;
import dev.sheldan.abstracto.core.command.execution.*;
import dev.sheldan.abstracto.utility.Utility;
@@ -14,7 +14,7 @@ import java.util.ArrayList;
import java.util.List;
@Component
public class Reject extends AbstractFeatureFlaggedCommand {
public class Reject extends AbstractConditionableCommand {
@Autowired
private SuggestionService suggestionService;

View File

@@ -1,6 +1,6 @@
package dev.sheldan.abstracto.utility.command.suggest;
import dev.sheldan.abstracto.core.command.AbstractFeatureFlaggedCommand;
import dev.sheldan.abstracto.core.command.AbstractConditionableCommand;
import dev.sheldan.abstracto.core.command.HelpInfo;
import dev.sheldan.abstracto.core.command.execution.*;
import dev.sheldan.abstracto.utility.Utility;
@@ -14,7 +14,7 @@ import java.util.ArrayList;
import java.util.List;
@Component
public class Suggest extends AbstractFeatureFlaggedCommand {
public class Suggest extends AbstractConditionableCommand {
@Autowired
private SuggestionService suggestionService;

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.utility.listener;
import dev.sheldan.abstracto.core.listener.MessageReceivedListener;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserManagementService;
@@ -57,15 +58,14 @@ public class MessageEmbedListener implements MessageReceivedListener {
@Autowired
private TemplateService templateService;
@Autowired
private ChannelService channelService;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createEmbedAndPostEmbed(@Nonnull Message postedMessage, CachedMessage message) {
MessageEmbeddedModel messageEmbeddedModel = buildTemplateParameter(postedMessage, message);
MessageToSend embed = templateService.renderEmbedTemplate(MESSAGE_EMBED_TEMPLATE, messageEmbeddedModel);
if(StringUtils.isBlank(embed.getMessage())) {
postedMessage.getChannel().sendMessage(embed.getEmbed()).queue();
} else {
postedMessage.getChannel().sendMessage(embed.getMessage()).embed(embed.getEmbed()).queue();
}
channelService.sendMessageToEndInTextChannel(embed, postedMessage.getTextChannel());
}
private MessageEmbeddedModel buildTemplateParameter(Message message, CachedMessage embeddedMessage) {

View File

@@ -70,8 +70,7 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
if(aEmote.isPresent()) {
AEmote emote = aEmote.get();
MessageReaction.ReactionEmote reactionEmote = addedReaction.getReactionEmote();
Optional<Emote> emoteInGuild = null;
emoteInGuild = bot.getEmote(guildId, emote);
Optional<Emote> emoteInGuild = bot.getEmote(guildId, emote);
if(EmoteUtils.isReactionEmoteAEmote(reactionEmote, emote, emoteInGuild.orElse(null))) {
Optional<CachedReaction> reactionOptional = EmoteUtils.getReactionFromMessageByEmote(message, emote);
updateStarboardPost(message, reactionOptional.orElse(null), userAdding, true);

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.utility.service;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.database.AChannel;
@@ -55,6 +56,9 @@ public class RemindServiceBean implements ReminderService {
@Autowired
private ReminderService self;
@Autowired
private ChannelService channelService;
@Override
public void createReminderInForUser(AUserInAServer user, String remindText, Duration remindIn, ReminderModel reminderModel) {
AChannel channel = channelManagementService.loadChannel(reminderModel.getChannel().getId());
@@ -69,12 +73,7 @@ public class RemindServiceBean implements ReminderService {
Reminder reminder = reminderManagementService.createReminder(aServerAChannelAUser, remindText, remindAt, reminderModel.getMessage().getIdLong());
reminderModel.setReminder(reminder);
MessageToSend message = templateService.renderEmbedTemplate(REMINDER_EMBED_KEY, reminderModel);
String messageText = message.getMessage();
if(StringUtils.isBlank(messageText)) {
reminderModel.getMessageChannel().sendMessage(message.getEmbed()).queue();
} else {
reminderModel.getMessageChannel().sendMessage(messageText).embed(message.getEmbed()).queue();
}
channelService.sendMessageToEndInAChannel(message, reminderModel.getChannel());
if(remindIn.getSeconds() < 60) {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
@@ -107,7 +106,7 @@ public class RemindServiceBean implements ReminderService {
.member(memberInServer)
.build();
MessageToSend messageToSend = templateService.renderEmbedTemplate("remind_reminder", build);
channelToAnswerIn.get().sendMessage(messageToSend.getMessage()).embed(messageToSend.getEmbed()).queue();
channelService.sendMessageToEndInTextChannel(messageToSend, channelToAnswerIn.get());
} else {
log.warn("Channel {} in server {} to remind user did not exist anymore. Ignoring reminder {}", channel.getId(), server.getId(), reminderId);
}

View File

@@ -29,6 +29,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
@@ -76,18 +77,24 @@ public class StarboardServiceBean implements StarboardService {
StarboardPostModel starboardPostModel = buildStarboardPostModel(message, userExceptAuthor.size());
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARBOARD_POST_TEMPLATE, starboardPostModel);
PostTarget starboard = postTargetManagement.getPostTarget(STARBOARD_POSTTARGET, message.getServerId());
postTargetService.sendEmbedInPostTarget(messageToSend, STARBOARD_POSTTARGET, message.getServerId()).thenAccept(message1 -> {
AServerChannelMessage aServerChannelMessage = AServerChannelMessage
.builder()
.messageId(message1.getIdLong())
.channel(starboard.getChannelReference())
.server(userReacting.getServerReference())
.build();
StarboardPost starboardPost = starboardPostManagementService.createStarboardPost(message, starredUser, userReacting, aServerChannelMessage);
// TODO maybe in bulk, but numbers should be small enough
userExceptAuthor.forEach(user -> {
starboardPostReactorManagementService.addReactor(starboardPost, user);
});
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, STARBOARD_POSTTARGET, message.getServerId());
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
try {
Message message1 = completableFutures.get(0).get();
AServerChannelMessage aServerChannelMessage = AServerChannelMessage
.builder()
.messageId(message1.getIdLong())
.channel(starboard.getChannelReference())
.server(userReacting.getServerReference())
.build();
StarboardPost starboardPost = starboardPostManagementService.createStarboardPost(message, starredUser, userReacting, aServerChannelMessage);
// TODO maybe in bulk, but numbers should be small enough
userExceptAuthor.forEach(user -> {
starboardPostReactorManagementService.addReactor(starboardPost, user);
});
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to post messages.", e);
}
});
}
@@ -126,10 +133,14 @@ public class StarboardServiceBean implements StarboardService {
public void updateStarboardPost(StarboardPost post, CachedMessage message, List<AUser> userExceptAuthor) {
StarboardPostModel starboardPostModel = buildStarboardPostModel(message, userExceptAuthor.size());
MessageToSend messageToSend = templateService.renderEmbedTemplate("starboard_post", starboardPostModel);
CompletableFuture<Message> future = new CompletableFuture<>();
postTargetService.editOrCreatedInPostTarget(post.getStarboardMessageId(), messageToSend, "starboard", message.getServerId(), future);
future.thenAccept(newOrOldMessage -> {
starboardPostManagementService.setStarboardPostMessageId(post, newOrOldMessage.getIdLong());
List<CompletableFuture<Message>> futures = new ArrayList<>();
postTargetService.editOrCreatedInPostTarget(post.getStarboardMessageId(), messageToSend, "starboard", message.getServerId(), futures);
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
try {
starboardPostManagementService.setStarboardPostMessageId(post, futures.get(0).get().getIdLong());
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to post starboard post.", e);
}
});
}

View File

@@ -21,7 +21,10 @@ import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@Component
@Slf4j
@@ -65,10 +68,16 @@ public class SuggestionServiceBean implements SuggestionService {
JDA instance = botService.getInstance();
Guild guildById = instance.getGuildById(guildId);
if(guildById != null) {
postTargetService.sendEmbedInPostTarget(messageToSend, SUGGESTIONS_TARGET, guildId).thenAccept(message -> {
suggestionManagementService.setPostedMessage(suggestion, message);
messageService.addReactionToMessage(SUGGESTION_YES_EMOTE, guildId, message);
messageService.addReactionToMessage(SUGGESTION_NO_EMOTE, guildId, message);
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SUGGESTIONS_TARGET, guildId);
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
try {
Message message = completableFutures.get(0).get();
suggestionManagementService.setPostedMessage(suggestion, message);
messageService.addReactionToMessage(SUGGESTION_YES_EMOTE, guildId, message);
messageService.addReactionToMessage(SUGGESTION_NO_EMOTE, guildId, message);
} catch (InterruptedException | ExecutionException e) {
log.warn("Failed to post suggestion", e);
}
});
} else {
log.warn("Guild {} or member {} was not found when creating suggestion.", member.getGuild().getIdLong(), member.getIdLong());

View File

@@ -2,11 +2,14 @@ package dev.sheldan.abstracto.core.command;
import dev.sheldan.abstracto.core.command.exception.IncorrectParameter;
import dev.sheldan.abstracto.core.command.exception.ParameterTooLong;
import dev.sheldan.abstracto.core.command.models.ACommand;
import dev.sheldan.abstracto.core.command.service.ChannelGroupCommandService;
import dev.sheldan.abstracto.core.command.service.PostCommandExecution;
import dev.sheldan.abstracto.core.command.execution.*;
import dev.sheldan.abstracto.core.command.meta.UnParsedCommandParameter;
import dev.sheldan.abstracto.core.Constants;
import dev.sheldan.abstracto.core.exception.*;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import dev.sheldan.abstracto.core.service.management.UserManagementService;
@@ -57,6 +60,12 @@ public class CommandReceivedHandler extends ListenerAdapter {
@Lazy
private CommandReceivedHandler self;
@Autowired
private ChannelGroupCommandService channelGroupCommandService;
@Autowired
private CommandManagementService commandManagementService;
@Override
@Async
@Transactional
@@ -85,8 +94,9 @@ public class CommandReceivedHandler extends ListenerAdapter {
CommandContext commandContext = commandContextBuilder.parameters(parsedParameters).build();
if(foundCommand instanceof ConditionalCommand) {
ConditionalCommand castedCommand = (ConditionalCommand) foundCommand;
if (!shouldExecute(commandContext, foundCommand, castedCommand.getConditions())) {
throw new FeatureDisabledException(String.format("Feature `%s` has been disabled. Command is not usable", foundCommand.getFeature()));
ConditionResult conditionResult = checkConditions(commandContext, foundCommand, castedCommand.getConditions());
if(!conditionResult.isResult()) {
throw new AbstractoRunTimeException(conditionResult.getReason());
}
}
CommandResult commandResult = self.executeCommand(foundCommand, commandContext);
@@ -107,14 +117,16 @@ public class CommandReceivedHandler extends ListenerAdapter {
return foundCommand.execute(commandContext);
}
public boolean shouldExecute(CommandContext commandContext, Command command, List<CommandCondition> conditions) {
AtomicBoolean shouldExecute = new AtomicBoolean(true);
public ConditionResult checkConditions(CommandContext commandContext, Command command, List<CommandCondition> conditions) {
if(conditions != null) {
conditions.forEach(condition -> {
shouldExecute.set(shouldExecute.get() && condition.shouldExecute(commandContext, command));
});
for (CommandCondition condition : conditions) {
ConditionResult conditionResult = condition.shouldExecute(commandContext, command);
if(!conditionResult.isResult()) {
return conditionResult;
}
}
}
return shouldExecute.get();
return ConditionResult.builder().result(true).build();
}
private UserInitiatedServerContext buildTemplateParameter(MessageReceivedEvent event) {
@@ -135,7 +147,7 @@ public class CommandReceivedHandler extends ListenerAdapter {
public Parameters getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message){
List<Object> parsedParameters = new ArrayList<>();
if(command.getConfiguration().getParameters().size() == 0) {
if(command.getConfiguration().getParameters() == null || command.getConfiguration().getParameters().size() == 0) {
return Parameters.builder().parameters(parsedParameters).build();
}
Iterator<TextChannel> channelIterator = message.getMentionedChannels().iterator();

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.core.command.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
public class ChannelGroupException extends AbstractoRunTimeException {
public ChannelGroupException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,9 @@
package dev.sheldan.abstracto.core.command.exception;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
public class CommandException extends AbstractoRunTimeException {
public CommandException(String message) {
super(message);
}
}

View File

@@ -23,6 +23,7 @@ public class ExceptionPostExecution implements PostCommandExecution {
if(commandResult.getResult().equals(ResultState.ERROR)) {
Throwable throwable = commandResult.getThrowable();
if(throwable != null) {
log.error("Exception: ", throwable);
if(throwable instanceof Templatable) {
Templatable exception = (Templatable) throwable;
String text = templateService.renderTemplate(exception.getTemplateName(), exception.getTemplateModel());

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.core.command.repository;
import dev.sheldan.abstracto.core.command.models.ACommand;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ChannelGroupCommandRepository extends JpaRepository<AChannelGroupCommand, Long> {
AChannelGroupCommand findByCommandAndGroup(ACommand command, AChannelGroup group);
List<AChannelGroupCommand> findByCommand(ACommand command);
}

View File

@@ -0,0 +1,36 @@
package dev.sheldan.abstracto.core.command.service;
import dev.sheldan.abstracto.core.command.models.ACommand;
import dev.sheldan.abstracto.core.command.service.management.ChannelGroupCommandManagementService;
import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Component
public class ChannelGroupCommandServiceBean implements ChannelGroupCommandService {
@Autowired
private ChannelGroupCommandManagementService channelGroupCommandService;
@Override
public Boolean isCommandEnabled(ACommand command, AChannel channel) {
List<AChannelGroupCommand> allChannelGroupsOfCommand = channelGroupCommandService.getAllGroupCommandsForCommand(command);
for (AChannelGroupCommand aChannelGroupCommand : allChannelGroupsOfCommand) {
Optional<AChannel> channelInGroup = aChannelGroupCommand.getGroup()
.getChannels().stream().filter(channel1 -> channel1.getId().equals(channel.getId())).findAny();
if (channelInGroup.isPresent()) {
if (aChannelGroupCommand.getEnabled()) {
return true;
}
}
}
if(allChannelGroupsOfCommand.size() == 0) {
return true;
}
return false;
}
}

View File

@@ -2,7 +2,6 @@ package dev.sheldan.abstracto.core.command.service;
import dev.sheldan.abstracto.core.command.models.ACommand;
import dev.sheldan.abstracto.core.command.models.AModule;
import dev.sheldan.abstracto.core.command.service.CommandService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.command.service.management.ModuleManagementService;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -0,0 +1,52 @@
package dev.sheldan.abstracto.core.command.service.management;
import dev.sheldan.abstracto.core.command.models.ACommand;
import dev.sheldan.abstracto.core.command.repository.ChannelGroupCommandRepository;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCommandManagementService {
@Autowired
private ChannelGroupCommandRepository groupCommandRepository;
@Override
public void setCommandInGroupTo(ACommand command, AChannelGroup group, Boolean enabled) {
AChannelGroupCommand groupCommand = groupCommandRepository.findByCommandAndGroup(command, group);
if(groupCommand == null) {
groupCommand = createCommandInGroupTo(command, group);
}
groupCommand.setEnabled(enabled);
groupCommandRepository.save(groupCommand);
}
@Override
public AChannelGroupCommand createCommandInGroupTo(ACommand command, AChannelGroup group) {
AChannelGroupCommand channelGroupCommand = AChannelGroupCommand
.builder()
.command(command)
.group(group)
.enabled(false)
.build();
groupCommandRepository.save(channelGroupCommand);
return channelGroupCommand;
}
@Override
public AChannelGroupCommand getChannelGroupCommand(ACommand command, AChannelGroup group) {
return groupCommandRepository.findByCommandAndGroup(command, group);
}
@Override
public List<AChannelGroupCommand> getAllGroupCommandsForCommand(ACommand command) {
return groupCommandRepository.findByCommand(command);
}
}

View File

@@ -37,7 +37,7 @@ public class AddToChannelGroup implements Command {
List<String> aliases = Arrays.asList("addTChGrp", "chGrpCh+");
return CommandConfiguration.builder()
.name("addToChannelGroup")
.module("channels")
.module(ChannelsModuleInterface.CHANNELS)
.aliases(aliases)
.parameters(parameters)
.description("Adds the mentioned channel to the channel group.")

View File

@@ -6,9 +6,12 @@ import org.springframework.stereotype.Component;
@Component
public class ChannelsModuleInterface implements ModuleInterface {
public static final String CHANNELS = "channels";
@Override
public ModuleInfo getInfo() {
return ModuleInfo.builder().name("channels").description("Includes utilities to configure the channel configuration stored in the database").build();
return ModuleInfo.builder().name(CHANNELS).description("Includes utilities to configure the channel configuration stored in the database").build();
}
@Override

View File

@@ -22,7 +22,7 @@ public class CreateChannelGroup implements Command {
@Override
public CommandResult execute(CommandContext commandContext) {
String groupName = (String) commandContext.getParameters().getParameters().get(0);
channelGroupService.createChannelGroup(groupName);
channelGroupService.createChannelGroup(groupName, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@@ -30,10 +30,12 @@ public class CreateChannelGroup implements Command {
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("name").type(String.class).description("The name of the channel group to create.").build();
List<Parameter> parameters = Arrays.asList(channelGroupName);
List<String> aliases = Arrays.asList("+ChGroup");
return CommandConfiguration.builder()
.name("createChannelGroup")
.module("channels")
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.aliases(aliases)
.description("Creates a channel group to which channels can be added to.")
.causesReaction(true)
.build();

View File

@@ -0,0 +1,48 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.execution.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.Parameter;
import dev.sheldan.abstracto.core.config.AbstractoFeatures;
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 DeleteChannelGroup implements Command {
@Autowired
private ChannelGroupService channelGroupService;
@Override
public CommandResult execute(CommandContext commandContext) {
String groupName = (String) commandContext.getParameters().getParameters().get(0);
channelGroupService.deleteChannelGroup(groupName, commandContext.getGuild().getIdLong());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("name").type(String.class).description("The name of the channel group to delete.").build();
List<Parameter> parameters = Arrays.asList(channelGroupName);
List<String> aliases = Arrays.asList("-ChGroup");
return CommandConfiguration.builder()
.name("deleteChannelGroup")
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.aliases(aliases)
.description("Removes an existing channel group.")
.causesReaction(true)
.build();
}
@Override
public String getFeature() {
return AbstractoFeatures.CORE;
}
}

View File

@@ -0,0 +1,48 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.execution.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.Parameter;
import dev.sheldan.abstracto.core.config.AbstractoFeatures;
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 DisableCommand implements Command {
@Autowired
private ChannelGroupService channelGroupService;
@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());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("commandName").type(String.class).description("The name of the channel group to add the channel to.").build();
Parameter channelToAdd = Parameter.builder().name("channelGroup").type(String.class).description("The name of the channel group in which the command should be disabled.").build();
List<Parameter> parameters = Arrays.asList(channelGroupName, channelToAdd);
return CommandConfiguration.builder()
.name("disableCommand")
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.description("Disables the given command in the given channel group.")
.causesReaction(true)
.build();
}
@Override
public String getFeature() {
return AbstractoFeatures.CORE;
}
}

View File

@@ -0,0 +1,48 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.execution.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.Parameter;
import dev.sheldan.abstracto.core.config.AbstractoFeatures;
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 EnableCommand implements Command {
@Autowired
private ChannelGroupService channelGroupService;
@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());
return CommandResult.fromSuccess();
}
@Override
public CommandConfiguration getConfiguration() {
Parameter channelGroupName = Parameter.builder().name("commandName").type(String.class).description("The name of the channel group to add the channel to.").build();
Parameter channelToAdd = Parameter.builder().name("channelGroup").type(String.class).description("The name of the channel group in which the command should be disabled.").build();
List<Parameter> parameters = Arrays.asList(channelGroupName, channelToAdd);
return CommandConfiguration.builder()
.name("enableCommand")
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.description("Disables the given command in the given channel group.")
.causesReaction(true)
.build();
}
@Override
public String getFeature() {
return AbstractoFeatures.CORE;
}
}

View File

@@ -0,0 +1,89 @@
package dev.sheldan.abstracto.core.commands.channels;
import dev.sheldan.abstracto.core.command.Command;
import dev.sheldan.abstracto.core.command.execution.CommandConfiguration;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.config.AbstractoFeatures;
import dev.sheldan.abstracto.core.models.MessageToSend;
import dev.sheldan.abstracto.core.models.command.ChannelGroupChannelModel;
import dev.sheldan.abstracto.core.models.command.ChannelGroupModel;
import dev.sheldan.abstracto.core.models.command.ListChannelGroupsModel;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.service.management.ChannelGroupManagementService;
import dev.sheldan.abstracto.templating.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 implements Command {
@Autowired
private TemplateService templateService;
@Autowired
private ChannelGroupManagementService channelGroupManagementService;
@Autowired
private ChannelService channelService;
@Override
public CommandResult execute(CommandContext commandContext) {
List<AChannelGroup> channelGroups = channelGroupManagementService.findAllInServer(commandContext.getUserInitiatedContext().getServer());
ListChannelGroupsModel template = (ListChannelGroupsModel) ContextConverter.fromCommandContext(commandContext, ListChannelGroupsModel.class);
template.setGroups(convertAChannelGroupToChannelGroupChannel(channelGroups));
MessageToSend response = templateService.renderEmbedTemplate("listChannelGroups_response", template);
channelService.sendMessageToEndInTextChannel(response, commandContext.getChannel());
return CommandResult.fromSuccess();
}
private List<ChannelGroupModel> convertAChannelGroupToChannelGroupChannel(List<AChannelGroup> channelGroups) {
List<ChannelGroupModel> converted = new ArrayList<>();
channelGroups.forEach(group -> {
List<ChannelGroupChannelModel> convertedChannels = new ArrayList<>();
group.getChannels().forEach(channel -> {
Optional<TextChannel> textChannelInGuild = channelService.getTextChannelInGuild(channel.getServer().getId(), channel.getId());
if(textChannelInGuild.isPresent()) {
ChannelGroupChannelModel convertedChannel = ChannelGroupChannelModel
.builder()
.channel(channel)
.discordChannel(textChannelInGuild.get())
.build();
convertedChannels.add(convertedChannel);
}
});
ChannelGroupModel channelGroup = ChannelGroupModel
.builder()
.name(group.getGroupName())
.channels(convertedChannels)
.build();
converted.add(channelGroup);
});
return converted;
}
@Override
public CommandConfiguration getConfiguration() {
List<String> aliases = Arrays.asList("lsChGrp");
return CommandConfiguration.builder()
.name("listChannelGroups")
.module(ChannelsModuleInterface.CHANNELS)
.aliases(aliases)
.description("Lists the current channel groups and their respective groups.")
.causesReaction(true)
.build();
}
@Override
public String getFeature() {
return AbstractoFeatures.CORE;
}
}

View File

@@ -65,7 +65,7 @@ public class PostTarget implements Command {
List<Parameter> parameters = Arrays.asList(postTargetName, channel);
return CommandConfiguration.builder()
.name("posttarget")
.module("channels")
.module(ChannelsModuleInterface.CHANNELS)
.parameters(parameters)
.description("Sets the target of a post done by the bot")
.causesReaction(true)

View File

@@ -37,7 +37,7 @@ public class RemoveFromChannelGroup implements Command {
List<String> aliases = Arrays.asList("rmChChgrp", "chGrpCh-");
return CommandConfiguration.builder()
.name("removeFromChannelGroup")
.module("channels")
.module(ChannelsModuleInterface.CHANNELS)
.aliases(aliases)
.parameters(parameters)
.description("Removes the mentioned channel from the channel group.")

View File

@@ -1,8 +1,12 @@
package dev.sheldan.abstracto.core.repository;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AServer;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ChannelGroupRepository extends JpaRepository<AChannelGroup, Long> {
AChannelGroup findByGroupName(String name);
AChannelGroup findByGroupNameAndServer(String name, AServer server);
List<AChannelGroup> findByServer(AServer server);
}

View File

@@ -1,9 +1,16 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.command.exception.ChannelGroupException;
import dev.sheldan.abstracto.core.command.exception.CommandException;
import dev.sheldan.abstracto.core.command.models.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.service.management.ChannelGroupManagementService;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
import net.dv8tion.jda.api.entities.TextChannel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -17,9 +24,25 @@ public class ChannelGroupServiceBean implements ChannelGroupService {
@Autowired
private ChannelManagementService channelManagementService;
@Autowired
private CommandManagementService commandManagementService;
@Autowired
private ChannelGroupCommandManagementService channelGroupCommandManagementService;
@Autowired
private ServerManagementService serverManagementService;
@Override
public AChannelGroup createChannelGroup(String name) {
return channelGroupManagementService.createChannelGroup(name);
public AChannelGroup createChannelGroup(String name, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
return channelGroupManagementService.createChannelGroup(name, server);
}
@Override
public void deleteChannelGroup(String name, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
channelGroupManagementService.deleteChannelGroup(name, server);
}
@Override
@@ -35,7 +58,11 @@ public class ChannelGroupServiceBean implements ChannelGroupService {
@Override
public void addChannelToChannelGroup(String channelGroupName, AChannel channel) {
AChannelGroup channelGroup = channelGroupManagementService.findByName(channelGroupName);
AServer server = serverManagementService.loadOrCreate(channel.getServer().getId());
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServer(channelGroupName, server);
if(channelGroup == null) {
throw new ChannelGroupException(String.format("Channel group %s was not found.", channelGroupName));
}
channelGroupManagementService.addChannelToChannelGroup(channelGroup, channel);
}
@@ -52,7 +79,45 @@ public class ChannelGroupServiceBean implements ChannelGroupService {
@Override
public void removeChannelFromChannelGroup(String channelGroupName, AChannel channel) {
AChannelGroup channelGroup = channelGroupManagementService.findByName(channelGroupName);
AServer server = serverManagementService.loadOrCreate(channel.getServer().getId());
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServer(channelGroupName, server);
if(channelGroup == null) {
throw new ChannelGroupException(String.format("Channel group %s was not found", channelGroupName));
}
channelGroupManagementService.removeChannelFromChannelGroup(channelGroup, channel);
}
@Override
public void disableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServer(channelGroupName, server);
if(channelGroup == null) {
throw new ChannelGroupException(String.format("Channel group %s was not found", channelGroupName));
}
ACommand command = commandManagementService.findCommandByName(commandName);
if(command == null) {
throw new CommandException(String.format("Command %s not found.", commandName));
}
channelGroupCommandManagementService.setCommandInGroupTo(command, channelGroup, false);
}
@Override
public void enableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
AChannelGroup channelGroup = channelGroupManagementService.findByNameAndServer(channelGroupName, server);
if(channelGroup == null) {
throw new ChannelGroupException(String.format("Channel group %s was not found", channelGroupName));
}
ACommand command = commandManagementService.findCommandByName(commandName);
if(command == null) {
throw new CommandException(String.format("Command %s not found.", commandName));
}
channelGroupCommandManagementService.setCommandInGroupTo(command, channelGroup, true);
}
@Override
public boolean doesGroupExist(String groupName, Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
return channelGroupManagementService.findByNameAndServer(groupName, server) != null;
}
}

View File

@@ -2,13 +2,22 @@ package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.exception.ChannelException;
import dev.sheldan.abstracto.core.exception.GuildException;
import dev.sheldan.abstracto.core.models.MessageToSend;
import dev.sheldan.abstracto.core.models.database.AChannel;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import net.dv8tion.jda.api.requests.restaction.MessageAction;
import org.apache.commons.lang3.StringUtils;
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.concurrent.CompletableFuture;
@Slf4j
@Component
public class ChannelServiceBean implements ChannelService {
@@ -32,4 +41,43 @@ public class ChannelServiceBean implements ChannelService {
throw new GuildException(String.format("Guild %s to post in channel %s was not found.", channel.getServer().getId(), channel.getId()));
}
}
@Override
public List<CompletableFuture<Message>> sendMessageToEndInAChannel(MessageToSend messageToSend, AChannel channel) {
Optional<TextChannel> textChannelFromServer = botService.getTextChannelFromServer(channel.getServer().getId(), channel.getId());
if(textChannelFromServer.isPresent()) {
return sendMessageToEndInTextChannel(messageToSend, textChannelFromServer.get());
}
throw new ChannelException(String.format("Channel %s was not found.", channel.getId()));
}
@Override
public List<CompletableFuture<Message>> sendMessageToEndInTextChannel(MessageToSend messageToSend, TextChannel textChannel) {
String messageText = messageToSend.getMessage();
List<CompletableFuture<Message>> futures = new ArrayList<>();
if(StringUtils.isBlank(messageText)) {
messageToSend.getEmbeds().forEach(embed -> {
CompletableFuture<Message> messageFuture = textChannel.sendMessage(embed).submit();
futures.add(messageFuture);
});
} else {
MessageAction messageAction = textChannel.sendMessage(messageText);
if(messageToSend.getEmbeds().size() > 0) {
CompletableFuture<Message> messageFuture = messageAction.embed(messageToSend.getEmbeds().get(0)).submit();
futures.add(messageFuture);
messageToSend.getEmbeds().stream().skip(1).forEach(embed -> {
CompletableFuture<Message> nextEmbedFuture = textChannel.sendMessage(embed).submit();
futures.add(nextEmbedFuture);
});
} else {
futures.add(messageAction.submit());
}
}
return futures;
}
@Override
public Optional<TextChannel> getTextChannelInGuild(Long serverId, Long channelId) {
return botService.getTextChannelFromServer(serverId, channelId);
}
}

View File

@@ -16,6 +16,7 @@ import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@@ -36,6 +37,9 @@ public class PostTargetServiceBean implements PostTargetService {
@Autowired
private DynamicKeyLoader dynamicKeyLoader;
@Autowired
private ChannelService channelService;
@Override
public CompletableFuture<Message> sendTextInPostTarget(String text, PostTarget target) {
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
@@ -88,46 +92,41 @@ public class PostTargetServiceBean implements PostTargetService {
}
@Override
public CompletableFuture<Message> sendEmbedInPostTarget(MessageToSend message, String postTargetName, Long serverId) {
public List<CompletableFuture<Message>> sendEmbedInPostTarget(MessageToSend message, String postTargetName, Long serverId) {
PostTarget postTarget = this.getPostTarget(postTargetName, serverId);
return this.sendEmbedInPostTarget(message, postTarget);
}
@Override
public CompletableFuture<Message> sendEmbedInPostTarget(MessageToSend message, PostTarget target) {
public List<CompletableFuture<Message>> sendEmbedInPostTarget(MessageToSend message, PostTarget target) {
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
String messageText = message.getMessage();
if(StringUtils.isBlank(messageText)) {
return textChannelForPostTarget.sendMessage(message.getEmbed()).submit();
} else {
return textChannelForPostTarget.sendMessage(messageText).embed(message.getEmbed()).submit();
}
return channelService.sendMessageToEndInTextChannel(message, textChannelForPostTarget);
}
@Override
public CompletableFuture<Message> editEmbedInPostTarget(Long messageId, MessageToSend message, PostTarget target) {
public List<CompletableFuture<Message>> editEmbedInPostTarget(Long messageId, MessageToSend message, PostTarget target) {
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
String messageText = message.getMessage();
if(StringUtils.isBlank(messageText)) {
return textChannelForPostTarget.editMessageById(messageId, message.getEmbed()).submit();
return Arrays.asList(textChannelForPostTarget.editMessageById(messageId, message.getEmbeds().get(0)).submit());
} else {
return textChannelForPostTarget.editMessageById(messageId, messageText).embed(message.getEmbed()).submit();
return Arrays.asList(textChannelForPostTarget.editMessageById(messageId, messageText).embed(message.getEmbeds().get(0)).submit());
}
}
@Override
public void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, PostTarget target, CompletableFuture<Message> future) {
public void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, PostTarget target, List<CompletableFuture<Message>> future) {
TextChannel textChannelForPostTarget = getTextChannelForPostTarget(target);
if(StringUtils.isBlank(messageToSend.getMessage().trim())) {
textChannelForPostTarget
.retrieveMessageById(messageId)
.queue(
existingMessage -> existingMessage
.editMessage(messageToSend.getEmbed())
.submit().thenAccept(future::complete),
.editMessage(messageToSend.getEmbeds().get(0))
.submit().thenAccept(message -> future.get(0).complete(message)),
throwable -> {
sendEmbedInPostTarget(messageToSend, target)
.thenAccept(future::complete);
sendEmbedInPostTarget(messageToSend, target).get(0)
.thenAccept(message -> future.get(0).complete(message));
});
} else {
textChannelForPostTarget
@@ -135,17 +134,17 @@ public class PostTargetServiceBean implements PostTargetService {
.queue(
existingMessage -> existingMessage
.editMessage(messageToSend.getMessage())
.embed(messageToSend.getEmbed())
.submit().thenAccept(future::complete),
.embed(messageToSend.getEmbeds().get(0))
.submit().thenAccept(message -> future.get(0).complete(message)),
throwable -> {
sendEmbedInPostTarget(messageToSend, target)
.thenAccept(future::complete);
sendEmbedInPostTarget(messageToSend, target).get(0)
.thenAccept(message -> future.get(0).complete(message));
});
}
}
@Override
public void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, String postTargetName, Long serverId, CompletableFuture<Message> future) {
public void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, String postTargetName, Long serverId, List<CompletableFuture<Message>> future) {
PostTarget postTarget = this.getPostTarget(postTargetName, serverId);
this.editOrCreatedInPostTarget(messageId, messageToSend, postTarget, future);
}
@@ -159,7 +158,7 @@ public class PostTargetServiceBean implements PostTargetService {
}
@Override
public CompletableFuture<Message> editEmbedInPostTarget(Long messageId, MessageToSend message, String postTargetName, Long serverId) {
public List<CompletableFuture<Message>> editEmbedInPostTarget(Long messageId, MessageToSend message, String postTargetName, Long serverId) {
PostTarget postTarget = this.getPostTarget(postTargetName, serverId);
return editEmbedInPostTarget(messageId, message, postTarget);
}

View File

@@ -1,12 +1,15 @@
package dev.sheldan.abstracto.core.service.management;
import dev.sheldan.abstracto.core.command.exception.ChannelGroupException;
import dev.sheldan.abstracto.core.exception.ChannelException;
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.repository.ChannelGroupRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.function.Predicate;
@Component
@@ -15,19 +18,37 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
@Autowired
private ChannelGroupRepository channelGroupRepository;
@Autowired
private ServerManagementService serverManagementService;
@Override
public AChannelGroup createChannelGroup(String name) {
public AChannelGroup createChannelGroup(String name, AServer server) {
name = name.toLowerCase();
AChannelGroup channelGroup = AChannelGroup
.builder()
.groupName(name)
.server(server)
.build();
channelGroupRepository.save(channelGroup);
return channelGroup;
}
@Override
public void deleteChannelGroup(String name, AServer server) {
name = name.toLowerCase();
AChannelGroup existing = findByNameAndServer(name, server);
if(existing == null) {
throw new ChannelGroupException(String.format("Channel group %s does not exist", name));
}
channelGroupRepository.delete(existing);
}
@Override
public AChannelGroup addChannelToChannelGroup(AChannelGroup channelGroup, AChannel channel) {
Predicate<AChannel> channelInGroupPredicate = channel1 -> channel1.getId().equals(channel.getId());
if(channelGroup == null) {
throw new ChannelGroupException("Channel group was not found.");
}
if(channelGroup.getChannels().stream().anyMatch(channelInGroupPredicate)) {
throw new ChannelException(String.format("Channel %s is already part of group %s.", channel.getId(), channelGroup.getGroupName()));
}
@@ -49,7 +70,19 @@ public class ChannelGroupManagementServiceBean implements ChannelGroupManagement
}
@Override
public AChannelGroup findByName(String name) {
return channelGroupRepository.findByGroupName(name);
public AChannelGroup findByNameAndServer(String name, AServer server) {
name = name.toLowerCase();
return channelGroupRepository.findByGroupNameAndServer(name, server);
}
@Override
public List<AChannelGroup> findAllInServer(AServer server) {
return channelGroupRepository.findByServer(server);
}
@Override
public List<AChannelGroup> findAllInServer(Long serverId) {
AServer server = serverManagementService.loadOrCreate(serverId);
return findAllInServer(server);
}
}

View File

@@ -0,0 +1 @@
abstracto.emoteNames.postReaction=warnReaction,successReaction

View File

@@ -0,0 +1,23 @@
{
"title": {
"title": "Current configured channel groups"
},
"color" : {
"r": 200,
"g": 0,
"b": 255
},
"fields": [
<#list groups as group>
{
"name": "${group.name}",
"value": "
<#list group.channels as channel>
${channel.discordChannel.asMention}
<#sep>,
</#list>
"
}<#sep>,
</#list>
]
}

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.core.command;
import dev.sheldan.abstracto.core.service.ChannelService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -7,13 +8,20 @@ import java.util.Arrays;
import java.util.List;
@Component
public abstract class AbstractFeatureFlaggedCommand implements ConditionalCommand {
public abstract class AbstractConditionableCommand implements ConditionalCommand {
@Autowired
private FeatureEnabledCondition featureEnabledCondition;
@Autowired
private CommandDisabledCondition commandDisabledCondition;
@Autowired
protected ChannelService channelService;
@Override
public List<CommandCondition> getConditions() {
return Arrays.asList(featureEnabledCondition);
return Arrays.asList(featureEnabledCondition, commandDisabledCondition);
}
}

View File

@@ -4,5 +4,5 @@ package dev.sheldan.abstracto.core.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
public interface CommandCondition {
boolean shouldExecute(CommandContext commandContext, Command command);
ConditionResult shouldExecute(CommandContext commandContext, Command command);
}

View File

@@ -0,0 +1,25 @@
package dev.sheldan.abstracto.core.command;
import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.models.ACommand;
import dev.sheldan.abstracto.core.command.service.ChannelGroupCommandService;
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CommandDisabledCondition implements CommandCondition {
@Autowired
private ChannelGroupCommandService channelGroupCommandService;
@Autowired
private CommandManagementService commandManagementService;
@Override
public ConditionResult shouldExecute(CommandContext context, Command command) {
ACommand acommand = commandManagementService.findCommandByName(command.getConfiguration().getName());
Boolean booleanResult = channelGroupCommandService.isCommandEnabled(acommand, context.getUserInitiatedContext().getChannel());
return ConditionResult.builder().result(booleanResult).reason("Command is disabled.").build();
}
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.core.command;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class ConditionResult {
private boolean result;
private String reason;
}

View File

@@ -12,11 +12,14 @@ public class FeatureEnabledCondition implements CommandCondition {
private FeatureFlagManagementService featureFlagManagementService;
@Override
public boolean shouldExecute(CommandContext context, Command command) {
public ConditionResult shouldExecute(CommandContext context, Command command) {
String featureName = command.getFeature();
boolean featureFlagValue = false;
String reason = "";
if(featureName != null) {
return featureFlagManagementService.getFeatureFlagValue(featureName, context.getGuild().getIdLong());
featureFlagValue = featureFlagManagementService.getFeatureFlagValue(featureName, context.getGuild().getIdLong());
reason = "Feature has been disabled.";
}
return false;
return ConditionResult.builder().reason(reason).result(featureFlagValue).build();
}
}

View File

@@ -1,32 +0,0 @@
package dev.sheldan.abstracto.core.command.models;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import lombok.*;
import javax.persistence.*;
@Entity
@Table(name = "channel_group_command")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class AChannelGroupCommand {
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "command_id", nullable = false)
@Getter
@Setter
@Column
private ACommand command;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id", nullable = false)
@Getter
@Setter
@Column
private AChannelGroup group;
private Boolean enabled;
}

View File

@@ -0,0 +1,8 @@
package dev.sheldan.abstracto.core.command.service;
import dev.sheldan.abstracto.core.command.models.ACommand;
import dev.sheldan.abstracto.core.models.database.AChannel;
public interface ChannelGroupCommandService {
Boolean isCommandEnabled(ACommand command, AChannel channel);
}

View File

@@ -0,0 +1,14 @@
package dev.sheldan.abstracto.core.command.service.management;
import dev.sheldan.abstracto.core.command.models.ACommand;
import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import java.util.List;
public interface ChannelGroupCommandManagementService {
void setCommandInGroupTo(ACommand command, AChannelGroup group, Boolean enabled);
AChannelGroupCommand createCommandInGroupTo(ACommand command, AChannelGroup group);
AChannelGroupCommand getChannelGroupCommand(ACommand command, AChannelGroup group);
List<AChannelGroupCommand> getAllGroupCommandsForCommand(ACommand command);
}

View File

@@ -5,10 +5,12 @@ import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.MessageEmbed;
import java.util.List;
@Getter
@Setter
@Builder
public class MessageToSend {
private MessageEmbed embed;
private List<MessageEmbed> embeds;
private String message;
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.models.command;
import dev.sheldan.abstracto.core.models.database.AChannel;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import net.dv8tion.jda.api.entities.TextChannel;
@Getter
@Setter
@Builder
public class ChannelGroupChannelModel {
private AChannel channel;
private TextChannel discordChannel;
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.models.command;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@Setter
@Builder
public class ChannelGroupModel {
private String name;
private List<ChannelGroupChannelModel> channels;
}

View File

@@ -0,0 +1,15 @@
package dev.sheldan.abstracto.core.models.command;
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;
import java.util.List;
@Getter
@Setter
@SuperBuilder
public class ListChannelGroupsModel extends UserInitiatedServerContext {
private List<ChannelGroupModel> groups;
}

View File

@@ -22,6 +22,12 @@ public class AChannelGroup {
@Setter
private String groupName;
@ManyToOne(fetch = FetchType.LAZY)
@Getter
@Setter
@JoinColumn(name = "group_server")
private AServer server;
@ManyToMany
@JoinTable(
name = "channel_in_group",

View File

@@ -13,20 +13,21 @@ import javax.persistence.*;
@Getter
public class AChannelGroupCommand {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long commandInGroupId;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "command_id", nullable = false)
@Getter
@Setter
@Column
private ACommand command;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "group_id", nullable = false)
@Getter
@Setter
@Column
private AChannelGroup group;
@Setter
private Boolean enabled;
}

View File

@@ -33,6 +33,14 @@ public class AServer implements SnowFlake {
@JoinColumn(name = "server_id")
private List<AChannel> channels = new ArrayList<>();
@OneToMany(
fetch = FetchType.LAZY,
cascade = CascadeType.ALL,
orphanRemoval = true)
@Builder.Default
@JoinColumn(name = "group_server")
private List<AChannelGroup> channelGroups = new ArrayList<>();
@OneToMany(
fetch = FetchType.LAZY,
mappedBy = "serverReference",

View File

@@ -5,11 +5,15 @@ import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import net.dv8tion.jda.api.entities.TextChannel;
public interface ChannelGroupService {
AChannelGroup createChannelGroup(String name);
AChannelGroup createChannelGroup(String name, Long serverId);
void deleteChannelGroup(String name, Long serverId);
void addChannelToChannelGroup(String channelGroupName, TextChannel textChannel);
void addChannelToChannelGroup(String channelGroupName, Long channelId);
void addChannelToChannelGroup(String channelGroupName, AChannel channel);
void removeChannelFromChannelGroup(String channelGroupName, TextChannel textChannel);
void removeChannelFromChannelGroup(String channelGroupName, Long channelId);
void removeChannelFromChannelGroup(String channelGroupName, AChannel channel);
void disableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId);
void enableCommandInChannelGroup(String commandName, String channelGroupName, Long serverId);
boolean doesGroupExist(String groupName, Long serverId);
}

View File

@@ -1,7 +1,17 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.models.MessageToSend;
import dev.sheldan.abstracto.core.models.database.AChannel;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.TextChannel;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
public interface ChannelService {
void sendTextInAChannel(String text, AChannel channel);
List<CompletableFuture<Message>> sendMessageToEndInAChannel(MessageToSend messageToSend, AChannel channel);
List<CompletableFuture<Message>> sendMessageToEndInTextChannel(MessageToSend messageToSend, TextChannel textChannel);
Optional<TextChannel> getTextChannelInGuild(Long serverId, Long channelId);
}

View File

@@ -13,12 +13,12 @@ public interface PostTargetService {
CompletableFuture<Message> sendEmbedInPostTarget(MessageEmbed embed, PostTarget target);
CompletableFuture<Message> sendTextInPostTarget(String text, String postTargetName, Long serverId);
CompletableFuture<Message> sendEmbedInPostTarget(MessageEmbed embed, String postTargetName, Long serverId);
CompletableFuture<Message> sendEmbedInPostTarget(MessageToSend message, String postTargetName, Long serverId);
CompletableFuture<Message> sendEmbedInPostTarget(MessageToSend message, PostTarget target);
CompletableFuture<Message> editEmbedInPostTarget(Long messageId, MessageToSend message, PostTarget target);
CompletableFuture<Message> editEmbedInPostTarget(Long messageId, MessageToSend message, String postTargetName, Long serverId);
void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, PostTarget target, CompletableFuture<Message> future);
void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, String postTarget, Long serverId, CompletableFuture<Message> future);
List<CompletableFuture<Message>> sendEmbedInPostTarget(MessageToSend message, String postTargetName, Long serverId);
List<CompletableFuture<Message>> sendEmbedInPostTarget(MessageToSend message, PostTarget target);
List<CompletableFuture<Message>> editEmbedInPostTarget(Long messageId, MessageToSend message, PostTarget target);
List<CompletableFuture<Message>> editEmbedInPostTarget(Long messageId, MessageToSend message, String postTargetName, Long serverId);
void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, PostTarget target, List<CompletableFuture<Message>> future);
void editOrCreatedInPostTarget(Long messageId, MessageToSend messageToSend, String postTarget, Long serverId, List<CompletableFuture<Message>> future);
void throwIfPostTargetIsNotDefined(String name, Long serverId);
boolean validPostTarget(String name);
List<String> getAvailablePostTargets();

View File

@@ -2,10 +2,16 @@ package dev.sheldan.abstracto.core.service.management;
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 java.util.List;
public interface ChannelGroupManagementService {
AChannelGroup createChannelGroup(String name);
AChannelGroup createChannelGroup(String name, AServer server);
void deleteChannelGroup(String name, AServer server);
AChannelGroup addChannelToChannelGroup(AChannelGroup channelGroup, AChannel channel);
void removeChannelFromChannelGroup(AChannelGroup channelGroup, AChannel channel);
AChannelGroup findByName(String name);
AChannelGroup findByNameAndServer(String name, AServer server);
List<AChannelGroup> findAllInServer(AServer server);
List<AChannelGroup> findAllInServer(Long serverId);
}

View File

@@ -18,6 +18,7 @@ import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import java.awt.*;
import java.io.IOException;
import java.time.Instant;
import java.util.Arrays;
import java.util.HashMap;
@Slf4j
@@ -91,7 +92,7 @@ public class TemplateServiceBean implements TemplateService {
return MessageToSend.builder()
.embed(builder.build())
.embeds(Arrays.asList(builder.build()))
.message(configuration.getAdditionalMessage())
.build();
}