mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-04-24 14:40:14 +00:00
[AB-196] adding confirmation requirement to various commands
refactoring command received handler in order to re-use when confirmation has been given removing reaction from showSuggestion and remind command adding log message for message deleted message, in case the member left all commands from now on must work without the member field from the message, as this is not available when retrieving the message
This commit is contained in:
@@ -50,6 +50,7 @@ public class DeleteAssignableRolePlace extends AbstractConditionableCommand {
|
|||||||
.templated(true)
|
.templated(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
.async(true)
|
.async(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
.help(helpInfo)
|
.help(helpInfo)
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ public class SetExpRole extends AbstractConditionableCommand {
|
|||||||
.async(true)
|
.async(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
.help(helpInfo)
|
.help(helpInfo)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public class SyncRoles extends AbstractConditionableCommand {
|
|||||||
.module(ExperienceModuleDefinition.EXPERIENCE)
|
.module(ExperienceModuleDefinition.EXPERIENCE)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
.async(true)
|
.async(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ public class UnSetExpRole extends AbstractConditionableCommand {
|
|||||||
.templated(true)
|
.templated(true)
|
||||||
.async(true)
|
.async(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
.help(helpInfo)
|
.help(helpInfo)
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public class RemoveTrackedInviteLinks extends AbstractConditionableCommand {
|
|||||||
.module(InviteFilterModerationModuleDefinition.MODERATION)
|
.module(InviteFilterModerationModuleDefinition.MODERATION)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
.async(true)
|
.async(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
|
|||||||
@@ -65,7 +65,10 @@ public class MessageDeleteLogListener implements AsyncMessageDeletedListener {
|
|||||||
CachedMessage message = model.getCachedMessage();
|
CachedMessage message = model.getCachedMessage();
|
||||||
memberService.getMemberInServerAsync(model.getServerId(), message.getAuthor().getAuthorId()).thenAccept(member ->
|
memberService.getMemberInServerAsync(model.getServerId(), message.getAuthor().getAuthorId()).thenAccept(member ->
|
||||||
self.executeListener(message, member)
|
self.executeListener(message, member)
|
||||||
);
|
).exceptionally(throwable -> {
|
||||||
|
log.warn("Could not retrieve member {} for message deleted event in guild {}.", message.getAuthor().getAuthorId(), model.getServerId(), throwable);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
return DefaultListenerResult.PROCESSED;
|
return DefaultListenerResult.PROCESSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public class DecayAllWarnings extends AbstractConditionableCommand {
|
|||||||
.module(ModerationModuleDefinition.MODERATION)
|
.module(ModerationModuleDefinition.MODERATION)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
.async(true)
|
.async(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public class DecayWarnings extends AbstractConditionableCommand {
|
|||||||
.name("decayWarnings")
|
.name("decayWarnings")
|
||||||
.module(ModerationModuleDefinition.MODERATION)
|
.module(ModerationModuleDefinition.MODERATION)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.async(true)
|
.async(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public class AnonReply extends AbstractConditionableCommand {
|
|||||||
ModMailThread thread = modMailThreadManagementService.getByChannel(channel);
|
ModMailThread thread = modMailThreadManagementService.getByChannel(channel);
|
||||||
Long threadId = thread.getId();
|
Long threadId = thread.getId();
|
||||||
return memberService.getMemberInServerAsync(thread.getUser()).thenCompose(member ->
|
return memberService.getMemberInServerAsync(thread.getUser()).thenCompose(member ->
|
||||||
modMailThreadService.relayMessageToDm(threadId, text, commandContext.getMessage(), true, commandContext.getChannel(), commandContext.getUndoActions(), member)
|
modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), true, member)
|
||||||
).thenApply(aVoid -> CommandResult.fromSuccess());
|
).thenApply(aVoid -> CommandResult.fromSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class Reply extends AbstractConditionableCommand {
|
|||||||
ModMailThread thread = modMailThreadManagementService.getByChannel(channel);
|
ModMailThread thread = modMailThreadManagementService.getByChannel(channel);
|
||||||
Long threadId = thread.getId();
|
Long threadId = thread.getId();
|
||||||
return memberService.getMemberInServerAsync(thread.getUser()).thenCompose(member ->
|
return memberService.getMemberInServerAsync(thread.getUser()).thenCompose(member ->
|
||||||
modMailThreadService.relayMessageToDm(threadId, text, commandContext.getMessage(), false, commandContext.getChannel(), commandContext.getUndoActions(), member)
|
modMailThreadService.loadExecutingMemberAndRelay(threadId, text, commandContext.getMessage(), false, member)
|
||||||
).thenApply(aVoid -> CommandResult.fromSuccess());
|
).thenApply(aVoid -> CommandResult.fromSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -553,8 +553,14 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public CompletableFuture<Void> relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions, Member targetMember) {
|
public CompletableFuture<Void> loadExecutingMemberAndRelay(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, Member targetMember) {
|
||||||
log.info("Relaying message {} to user {} in modmail thread {} on server {}.", replyCommandMessage.getId(), targetMember.getId(), modmailThreadId, targetMember.getGuild().getId());
|
log.info("Relaying message {} to user {} in modmail thread {} on server {}.", replyCommandMessage.getId(), targetMember.getId(), modmailThreadId, targetMember.getGuild().getId());
|
||||||
|
return memberService.getMemberInServerAsync(replyCommandMessage.getGuild().getIdLong(), replyCommandMessage.getAuthor().getIdLong())
|
||||||
|
.thenCompose(executingMember -> self.relayMessageToDm(modmailThreadId, text, replyCommandMessage, anonymous, targetMember, executingMember));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public CompletableFuture<Void> relayMessageToDm(Long modmailThreadId, String text, Message replyCommandMessage, boolean anonymous, Member targetMember, Member executingMember) {
|
||||||
metricService.incrementCounter(MDOMAIL_THREAD_MESSAGE_SENT);
|
metricService.incrementCounter(MDOMAIL_THREAD_MESSAGE_SENT);
|
||||||
ModMailThread modMailThread = modMailThreadManagementService.getById(modmailThreadId);
|
ModMailThread modMailThread = modMailThreadManagementService.getById(modmailThreadId);
|
||||||
FullUserInServer fullThreadUser = FullUserInServer
|
FullUserInServer fullThreadUser = FullUserInServer
|
||||||
@@ -573,7 +579,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
|||||||
log.debug("Message is sent anonymous.");
|
log.debug("Message is sent anonymous.");
|
||||||
modMailModeratorReplyModelBuilder.moderator(memberService.getBotInGuild(modMailThread.getServer()));
|
modMailModeratorReplyModelBuilder.moderator(memberService.getBotInGuild(modMailThread.getServer()));
|
||||||
} else {
|
} else {
|
||||||
modMailModeratorReplyModelBuilder.moderator(replyCommandMessage.getMember());
|
modMailModeratorReplyModelBuilder.moderator(executingMember);
|
||||||
}
|
}
|
||||||
ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build();
|
ModMailModeratorReplyModel modMailUserReplyModel = modMailModeratorReplyModelBuilder.build();
|
||||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY, modMailUserReplyModel, modMailThread.getServer().getId());
|
MessageToSend messageToSend = templateService.renderEmbedTemplate(MODMAIL_STAFF_MESSAGE_TEMPLATE_KEY, modMailUserReplyModel, modMailThread.getServer().getId());
|
||||||
|
|||||||
@@ -67,12 +67,10 @@ public interface ModMailThreadService {
|
|||||||
* @param text The parsed text of the reply
|
* @param text The parsed text of the reply
|
||||||
* @param message The pure {@link Message} containing the command which caused the reply
|
* @param message The pure {@link Message} containing the command which caused the reply
|
||||||
* @param anonymous Whether or nor the message should be send anonymous
|
* @param anonymous Whether or nor the message should be send anonymous
|
||||||
* @param feedBack The {@link MessageChannel} in which feedback about possible exceptions should be sent to
|
|
||||||
* @param undoActions A list of {@link dev.sheldan.abstracto.core.models.UndoAction actions} to be undone in case the operation fails. This list will be filled in the method.
|
|
||||||
* @param targetMember The {@link Member} the {@link ModMailThread} is about.
|
* @param targetMember The {@link Member} the {@link ModMailThread} is about.
|
||||||
* @return A {@link CompletableFuture future} which completes when the message has been relayed to the DM
|
* @return A {@link CompletableFuture future} which completes when the message has been relayed to the DM
|
||||||
*/
|
*/
|
||||||
CompletableFuture<Void> relayMessageToDm(Long threadId, String text, Message message, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions, Member targetMember);
|
CompletableFuture<Void> loadExecutingMemberAndRelay(Long threadId, String text, Message message, boolean anonymous, Member targetMember);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.TextChannel} associated with the mod mail thread,
|
* Closes the mod mail thread which means: deletes the {@link net.dv8tion.jda.api.entities.TextChannel} associated with the mod mail thread,
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class Remind extends AbstractConditionableCommand {
|
|||||||
.module(UtilityModuleDefinition.UTILITY)
|
.module(UtilityModuleDefinition.UTILITY)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(false)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
.help(helpInfo)
|
.help(helpInfo)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -109,7 +109,10 @@ public class RemindServiceBean implements ReminderService {
|
|||||||
} else {
|
} else {
|
||||||
HashMap<Object, Object> parameters = new HashMap<>();
|
HashMap<Object, Object> parameters = new HashMap<>();
|
||||||
parameters.put("reminderId", reminder.getId().toString());
|
parameters.put("reminderId", reminder.getId().toString());
|
||||||
JobParameters jobParameters = JobParameters.builder().parameters(parameters).build();
|
JobParameters jobParameters = JobParameters
|
||||||
|
.builder()
|
||||||
|
.parameters(parameters)
|
||||||
|
.build();
|
||||||
String triggerKey = schedulerService.executeJobWithParametersOnce("reminderJob", "utility", jobParameters, Date.from(reminder.getTargetDate()));
|
String triggerKey = schedulerService.executeJobWithParametersOnce("reminderJob", "utility", jobParameters, Date.from(reminder.getTargetDate()));
|
||||||
log.info("Starting scheduled job with trigger {} to execute reminder {}.", triggerKey, reminder.getId());
|
log.info("Starting scheduled job with trigger {} to execute reminder {}.", triggerKey, reminder.getId());
|
||||||
reminder.setJobTriggerKey(triggerKey);
|
reminder.setJobTriggerKey(triggerKey);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public class PurgeImagePosts extends AbstractConditionableCommand {
|
|||||||
.module(RepostDetectionModuleDefinition.REPOST_DETECTION)
|
.module(RepostDetectionModuleDefinition.REPOST_DETECTION)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
.async(false)
|
.async(false)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public class PurgeReposts extends AbstractConditionableCommand {
|
|||||||
.module(RepostDetectionModuleDefinition.REPOST_DETECTION)
|
.module(RepostDetectionModuleDefinition.REPOST_DETECTION)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
.async(false)
|
.async(false)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ public class DeleteTrackedEmote extends AbstractConditionableCommand {
|
|||||||
.templated(true)
|
.templated(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
.help(helpInfo)
|
.help(helpInfo)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ public class PurgeEmoteStats extends AbstractConditionableCommand {
|
|||||||
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
|
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
.help(helpInfo)
|
.help(helpInfo)
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public class ResetEmoteStats extends AbstractConditionableCommand {
|
|||||||
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
|
.module(EmoteTrackingModuleDefinition.EMOTE_TRACKING)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
.help(helpInfo)
|
.help(helpInfo)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class ShowSuggestion extends AbstractConditionableCommand {
|
|||||||
.templated(true)
|
.templated(true)
|
||||||
.async(true)
|
.async(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.causesReaction(true)
|
.causesReaction(false)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
.help(helpInfo)
|
.help(helpInfo)
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -114,7 +114,13 @@ public class SuggestionServiceBean implements SuggestionService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> createSuggestionMessage(Message commandMessage, String text) {
|
public CompletableFuture<Void> createSuggestionMessage(Message commandMessage, String text) {
|
||||||
Member suggester = commandMessage.getMember();
|
// it is done that way, because we cannot always be sure, that the message containsn the member
|
||||||
|
return memberService.getMemberInServerAsync(commandMessage.getGuild().getIdLong(), commandMessage.getAuthor().getIdLong())
|
||||||
|
.thenCompose(suggester -> self.createMessageWithSuggester(commandMessage, text, suggester));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public CompletableFuture<Void> createMessageWithSuggester(Message commandMessage, String text, Member suggester) {
|
||||||
Long serverId = suggester.getGuild().getIdLong();
|
Long serverId = suggester.getGuild().getIdLong();
|
||||||
AServer server = serverManagementService.loadServer(serverId);
|
AServer server = serverManagementService.loadServer(serverId);
|
||||||
AUserInAServer userSuggester = userInServerManagementService.loadOrCreateUser(suggester);
|
AUserInAServer userSuggester = userInServerManagementService.loadOrCreateUser(suggester);
|
||||||
@@ -126,7 +132,7 @@ public class SuggestionServiceBean implements SuggestionService {
|
|||||||
.state(SuggestionState.NEW)
|
.state(SuggestionState.NEW)
|
||||||
.serverId(serverId)
|
.serverId(serverId)
|
||||||
.message(commandMessage)
|
.message(commandMessage)
|
||||||
.member(commandMessage.getMember())
|
.member(suggester)
|
||||||
.suggesterUser(userSuggester)
|
.suggesterUser(userSuggester)
|
||||||
.useButtons(useButtons)
|
.useButtons(useButtons)
|
||||||
.suggester(suggester.getUser())
|
.suggester(suggester.getUser())
|
||||||
@@ -210,22 +216,24 @@ public class SuggestionServiceBean implements SuggestionService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> acceptSuggestion(Long suggestionId, Message commandMessage, String text) {
|
public CompletableFuture<Void> acceptSuggestion(Long suggestionId, Message commandMessage, String text) {
|
||||||
|
return memberService.getMemberInServerAsync(commandMessage.getGuild().getIdLong(), commandMessage.getAuthor().getIdLong())
|
||||||
|
.thenCompose(member -> self.setSuggestionToFinalState(member, suggestionId, commandMessage, text, SuggestionState.ACCEPTED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public CompletableFuture<Void> setSuggestionToFinalState(Member executingMember, Long suggestionId, Message commandMessage, String text, SuggestionState state) {
|
||||||
Long serverId = commandMessage.getGuild().getIdLong();
|
Long serverId = commandMessage.getGuild().getIdLong();
|
||||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
||||||
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.ACCEPTED);
|
suggestionManagementService.setSuggestionState(suggestion, state);
|
||||||
cancelSuggestionReminder(suggestion);
|
cancelSuggestionReminder(suggestion);
|
||||||
log.info("Accepting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
|
log.info("Setting suggestion {} in server {} to state {}", suggestionId, suggestion.getServer().getId(), state);
|
||||||
return updateSuggestion(commandMessage.getMember(), text, suggestion);
|
return updateSuggestion(executingMember, text, suggestion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> vetoSuggestion(Long suggestionId, Message commandMessage, String text) {
|
public CompletableFuture<Void> vetoSuggestion(Long suggestionId, Message commandMessage, String text) {
|
||||||
Long serverId = commandMessage.getGuild().getIdLong();
|
return memberService.getMemberInServerAsync(commandMessage.getGuild().getIdLong(), commandMessage.getAuthor().getIdLong())
|
||||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
.thenCompose(member -> self.setSuggestionToFinalState(member, suggestionId, commandMessage, text, SuggestionState.VETOED));
|
||||||
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.VETOED);
|
|
||||||
cancelSuggestionReminder(suggestion);
|
|
||||||
log.info("Vetoing suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
|
|
||||||
return updateSuggestion(commandMessage.getMember(), text, suggestion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CompletableFuture<Void> updateSuggestion(Member memberExecutingCommand, String reason, Suggestion suggestion) {
|
private CompletableFuture<Void> updateSuggestion(Member memberExecutingCommand, String reason, Suggestion suggestion) {
|
||||||
@@ -293,12 +301,8 @@ public class SuggestionServiceBean implements SuggestionService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> rejectSuggestion(Long suggestionId, Message commandMessage, String text) {
|
public CompletableFuture<Void> rejectSuggestion(Long suggestionId, Message commandMessage, String text) {
|
||||||
Long serverId = commandMessage.getGuild().getIdLong();
|
return memberService.getMemberInServerAsync(commandMessage.getGuild().getIdLong(), commandMessage.getAuthor().getIdLong())
|
||||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
.thenCompose(member -> self.setSuggestionToFinalState(member, suggestionId, commandMessage, text, SuggestionState.REJECTED));
|
||||||
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.REJECTED);
|
|
||||||
cancelSuggestionReminder(suggestion);
|
|
||||||
log.info("Rejecting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
|
|
||||||
return updateSuggestion(commandMessage.getMember(), text, suggestion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
package dev.sheldan.abstracto.suggestion.service;
|
package dev.sheldan.abstracto.suggestion.service;
|
||||||
|
|
||||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
|
||||||
import dev.sheldan.abstracto.core.exception.ChannelNotInGuildException;
|
|
||||||
import dev.sheldan.abstracto.core.models.ServerSpecificId;
|
|
||||||
import dev.sheldan.abstracto.core.models.database.AChannel;
|
import dev.sheldan.abstracto.core.models.database.AChannel;
|
||||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||||
import dev.sheldan.abstracto.core.models.database.AUser;
|
|
||||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||||
import dev.sheldan.abstracto.core.service.*;
|
import dev.sheldan.abstracto.core.service.*;
|
||||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||||
@@ -16,10 +12,8 @@ import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition;
|
|||||||
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureMode;
|
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureMode;
|
||||||
import dev.sheldan.abstracto.suggestion.config.SuggestionPostTarget;
|
import dev.sheldan.abstracto.suggestion.config.SuggestionPostTarget;
|
||||||
import dev.sheldan.abstracto.suggestion.exception.SuggestionNotFoundException;
|
import dev.sheldan.abstracto.suggestion.exception.SuggestionNotFoundException;
|
||||||
import dev.sheldan.abstracto.suggestion.model.database.Suggestion;
|
|
||||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
||||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionUpdateModel;
|
|
||||||
import dev.sheldan.abstracto.suggestion.service.management.SuggestionManagementService;
|
import dev.sheldan.abstracto.suggestion.service.management.SuggestionManagementService;
|
||||||
import net.dv8tion.jda.api.entities.*;
|
import net.dv8tion.jda.api.entities.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -113,17 +107,12 @@ public class SuggestionServiceBeanTest {
|
|||||||
public void testCreateSuggestionMessage() {
|
public void testCreateSuggestionMessage() {
|
||||||
String suggestionText = "text";
|
String suggestionText = "text";
|
||||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||||
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
|
when(message.getAuthor()).thenReturn(suggesterUser);
|
||||||
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
|
when(message.getGuild()).thenReturn(guild);
|
||||||
when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_CREATION_TEMPLATE), any(SuggestionLog.class), eq(SERVER_ID))).thenReturn(messageToSend);
|
when(suggesterUser.getIdLong()).thenReturn(SUGGESTER_ID);
|
||||||
Message suggestionMessage = Mockito.mock(Message.class);
|
when(memberService.getMemberInServerAsync(SERVER_ID, SUGGESTER_ID)).thenReturn(CompletableFuture.completedFuture(member));
|
||||||
when(counterService.getNextCounterValue(server, SuggestionServiceBean.SUGGESTION_COUNTER_KEY)).thenReturn(SUGGESTION_ID);
|
|
||||||
List<CompletableFuture<Message>> postingFutures = Arrays.asList(CompletableFuture.completedFuture(suggestionMessage));
|
|
||||||
when(postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, SERVER_ID)).thenReturn(postingFutures);
|
|
||||||
when(message.getMember()).thenReturn(member);
|
|
||||||
when(member.getGuild()).thenReturn(guild);
|
|
||||||
when(member.getIdLong()).thenReturn(SUGGESTER_ID);
|
|
||||||
testUnit.createSuggestionMessage(message, suggestionText);
|
testUnit.createSuggestionMessage(message, suggestionText);
|
||||||
|
verify(self).createMessageWithSuggester(message, suggestionText, member);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -139,20 +128,26 @@ public class SuggestionServiceBeanTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test(expected = SuggestionNotFoundException.class)
|
@Test
|
||||||
public void testAcceptNotExistingSuggestion() {
|
public void testAcceptNotExistingSuggestion() {
|
||||||
when(suggestionManagementService.getSuggestion(SERVER_ID, SUGGESTION_ID)).thenThrow(new SuggestionNotFoundException(SUGGESTION_ID));
|
|
||||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||||
when(message.getGuild()).thenReturn(guild);
|
when(message.getGuild()).thenReturn(guild);
|
||||||
|
when(message.getAuthor()).thenReturn(suggesterUser);
|
||||||
|
when(suggesterUser.getIdLong()).thenReturn(SUGGESTER_ID);
|
||||||
|
when(memberService.getMemberInServerAsync(SERVER_ID, SUGGESTER_ID)).thenReturn(CompletableFuture.completedFuture(member));
|
||||||
testUnit.acceptSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
testUnit.acceptSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||||
|
verify(self).setSuggestionToFinalState(member, SUGGESTION_ID, message, CLOSING_TEXT, SuggestionState.ACCEPTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = SuggestionNotFoundException.class)
|
@Test
|
||||||
public void testRejectNotExistingSuggestion() {
|
public void testRejectNotExistingSuggestion() {
|
||||||
when(suggestionManagementService.getSuggestion(SERVER_ID, SUGGESTION_ID)).thenThrow(new SuggestionNotFoundException(SUGGESTION_ID));
|
|
||||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||||
when(message.getGuild()).thenReturn(guild);
|
when(message.getGuild()).thenReturn(guild);
|
||||||
|
when(message.getAuthor()).thenReturn(suggesterUser);
|
||||||
|
when(suggesterUser.getIdLong()).thenReturn(SUGGESTER_ID);
|
||||||
|
when(memberService.getMemberInServerAsync(SERVER_ID, SUGGESTER_ID)).thenReturn(CompletableFuture.completedFuture(member));
|
||||||
testUnit.rejectSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
testUnit.rejectSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||||
|
verify(self).setSuggestionToFinalState(member, SUGGESTION_ID, message, CLOSING_TEXT, SuggestionState.REJECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ package dev.sheldan.abstracto.core.command;
|
|||||||
|
|
||||||
import dev.sheldan.abstracto.core.command.condition.ConditionResult;
|
import dev.sheldan.abstracto.core.command.condition.ConditionResult;
|
||||||
import dev.sheldan.abstracto.core.command.config.*;
|
import dev.sheldan.abstracto.core.command.config.*;
|
||||||
|
import dev.sheldan.abstracto.core.command.config.features.CoreFeatureConfig;
|
||||||
import dev.sheldan.abstracto.core.command.exception.CommandParameterValidationException;
|
import dev.sheldan.abstracto.core.command.exception.CommandParameterValidationException;
|
||||||
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterException;
|
import dev.sheldan.abstracto.core.command.exception.IncorrectParameterException;
|
||||||
import dev.sheldan.abstracto.core.command.exception.InsufficientParametersException;
|
import dev.sheldan.abstracto.core.command.exception.InsufficientParametersException;
|
||||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
import dev.sheldan.abstracto.core.command.execution.*;
|
||||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
|
||||||
import dev.sheldan.abstracto.core.command.execution.UnParsedCommandParameter;
|
|
||||||
import dev.sheldan.abstracto.core.command.execution.UnparsedCommandParameterPiece;
|
|
||||||
import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler;
|
import dev.sheldan.abstracto.core.command.handler.CommandParameterHandler;
|
||||||
import dev.sheldan.abstracto.core.command.handler.CommandParameterIterators;
|
import dev.sheldan.abstracto.core.command.handler.CommandParameterIterators;
|
||||||
|
import dev.sheldan.abstracto.core.command.model.CommandConfirmationModel;
|
||||||
|
import dev.sheldan.abstracto.core.command.model.CommandConfirmationPayload;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandManager;
|
import dev.sheldan.abstracto.core.command.service.CommandManager;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandService;
|
import dev.sheldan.abstracto.core.command.service.CommandService;
|
||||||
import dev.sheldan.abstracto.core.command.service.ExceptionService;
|
import dev.sheldan.abstracto.core.command.service.ExceptionService;
|
||||||
@@ -20,10 +20,16 @@ import dev.sheldan.abstracto.core.metric.service.CounterMetric;
|
|||||||
import dev.sheldan.abstracto.core.metric.service.MetricService;
|
import dev.sheldan.abstracto.core.metric.service.MetricService;
|
||||||
import dev.sheldan.abstracto.core.metric.service.MetricTag;
|
import dev.sheldan.abstracto.core.metric.service.MetricTag;
|
||||||
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
|
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
|
||||||
import dev.sheldan.abstracto.core.service.EmoteService;
|
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||||
import dev.sheldan.abstracto.core.service.RoleService;
|
import dev.sheldan.abstracto.core.service.*;
|
||||||
import dev.sheldan.abstracto.core.service.management.*;
|
import dev.sheldan.abstracto.core.service.management.*;
|
||||||
|
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||||
|
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||||
|
import dev.sheldan.abstracto.scheduling.model.JobParameters;
|
||||||
|
import dev.sheldan.abstracto.scheduling.service.SchedulerService;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.dv8tion.jda.api.entities.*;
|
import net.dv8tion.jda.api.entities.*;
|
||||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||||
@@ -35,6 +41,8 @@ import org.springframework.transaction.annotation.Isolation;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -88,6 +96,32 @@ public class CommandReceivedHandler extends ListenerAdapter {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private MetricService metricService;
|
private MetricService metricService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ComponentService componentService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ComponentPayloadManagementService componentPayloadManagementService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ComponentPayloadService componentPayloadService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TemplateService templateService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ChannelService channelService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SchedulerService schedulerService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ConfigService configService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MessageService messageService;
|
||||||
|
|
||||||
|
public static final String COMMAND_CONFIRMATION_ORIGIN = "commandConfirmation";
|
||||||
|
public static final String COMMAND_CONFIRMATION_MESSAGE_TEMPLATE_KEY = "command_confirmation_message";
|
||||||
public static final String COMMAND_PROCESSED = "command.processed";
|
public static final String COMMAND_PROCESSED = "command.processed";
|
||||||
public static final String STATUS_TAG = "status";
|
public static final String STATUS_TAG = "status";
|
||||||
public static final CounterMetric COMMANDS_PROCESSED_COUNTER = CounterMetric
|
public static final CounterMetric COMMANDS_PROCESSED_COUNTER = CounterMetric
|
||||||
@@ -107,38 +141,105 @@ public class CommandReceivedHandler extends ListenerAdapter {
|
|||||||
if(!event.isFromGuild()) {
|
if(!event.isFromGuild()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!commandManager.isCommand(event.getMessage())) {
|
Message message = event.getMessage();
|
||||||
|
if(!commandManager.isCommand(message)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
metricService.incrementCounter(COMMANDS_PROCESSED_COUNTER);
|
metricService.incrementCounter(COMMANDS_PROCESSED_COUNTER);
|
||||||
final Command foundCommand;
|
|
||||||
try {
|
try {
|
||||||
String contentStripped = event.getMessage().getContentRaw();
|
UnParsedCommandResult result = getUnparsedCommandResult(message);
|
||||||
List<String> parameters = Arrays.asList(contentStripped.split(" "));
|
CompletableFuture<CommandParseResult> parsingFuture = getParametersFromMessage(message, result);
|
||||||
UnParsedCommandParameter unParsedParameter = new UnParsedCommandParameter(contentStripped, event.getMessage());
|
parsingFuture.thenAccept(parsedParameters ->
|
||||||
String commandName = commandManager.getCommandName(parameters.get(0), event.getGuild().getIdLong());
|
self.executeCommand(event, parsedParameters.getCommand(), parsedParameters.getParameters())
|
||||||
foundCommand = commandManager.findCommandByParameters(commandName, unParsedParameter, event.getGuild().getIdLong());
|
).exceptionally(throwable -> {
|
||||||
tryToExecuteFoundCommand(event, foundCommand, unParsedParameter);
|
self.reportException(event, result.getCommand(), throwable, "Exception when executing or parsing command.");
|
||||||
|
return null;
|
||||||
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
reportException(event, null, e, String.format("Exception when executing command from message %d in message %d in guild %d."
|
reportException(event, null, e, String.format("Exception when executing command from message %d in message %d in guild %d."
|
||||||
,event.getMessage().getIdLong(), event.getChannel().getIdLong(), event.getGuild().getIdLong()));
|
, message.getIdLong(), event.getChannel().getIdLong(), event.getGuild().getIdLong()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryToExecuteFoundCommand(MessageReceivedEvent event, Command foundCommand, UnParsedCommandParameter unParsedParameter) {
|
public UnParsedCommandResult getUnparsedCommandResult(Message message) {
|
||||||
CompletableFuture<Parameters> parsingFuture = getParsedParameters(unParsedParameter, foundCommand, event.getMessage());
|
String contentStripped = message.getContentRaw();
|
||||||
parsingFuture.thenAccept(parsedParameters ->
|
List<String> parameters = Arrays.asList(contentStripped.split(" "));
|
||||||
self.executeCommand(event, foundCommand, parsedParameters)
|
UnParsedCommandParameter unParsedParameter = new UnParsedCommandParameter(contentStripped, message);
|
||||||
).exceptionally(throwable -> {
|
String commandName = commandManager.getCommandName(parameters.get(0), message.getGuild().getIdLong());
|
||||||
self.reportException(event, foundCommand, throwable, "Exception when executing or parsing command.");
|
Command foundCommand = commandManager.findCommandByParameters(commandName, unParsedParameter, message.getGuild().getIdLong());
|
||||||
return null;
|
return UnParsedCommandResult
|
||||||
});
|
.builder()
|
||||||
|
.command(foundCommand)
|
||||||
|
.parameter(unParsedParameter)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<CommandParseResult> getParametersFromMessage(Message message) {
|
||||||
|
UnParsedCommandResult result = getUnparsedCommandResult(message);
|
||||||
|
return getParsedParameters(result.getParameter(), result.getCommand(), message).thenApply(foundParameters -> CommandParseResult
|
||||||
|
.builder()
|
||||||
|
.command(result.getCommand())
|
||||||
|
.parameters(foundParameters)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<CommandParseResult> getParametersFromMessage(Message message, UnParsedCommandResult result) {
|
||||||
|
return getParsedParameters(result.getParameter(), result.getCommand(), message).thenApply(foundParameters -> CommandParseResult
|
||||||
|
.builder()
|
||||||
|
.command(result.getCommand())
|
||||||
|
.parameters(foundParameters)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public CompletableFuture<Void> cleanupConfirmationMessage(Long server, Long channelId, Long messageId, String confirmationPayloadId, String abortPayloadId) {
|
||||||
|
componentPayloadManagementService.deletePayloads(Arrays.asList(confirmationPayloadId, abortPayloadId));
|
||||||
|
return messageService.deleteMessageInChannelInServer(server, channelId, messageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void persistConfirmationCallbacks(CommandConfirmationModel model, Message createdMessage) {
|
||||||
|
AServer server = serverManagementService.loadServer(model.getDriedCommandContext().getServerId());
|
||||||
|
CommandConfirmationPayload confirmPayload = CommandConfirmationPayload
|
||||||
|
.builder()
|
||||||
|
.commandContext(model.getDriedCommandContext())
|
||||||
|
.otherButtonComponentId(model.getAbortButtonId())
|
||||||
|
.action(CommandConfirmationPayload.CommandConfirmationAction.CONFIRM)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
componentPayloadService.createButtonPayload(model.getConfirmButtonId(), confirmPayload, COMMAND_CONFIRMATION_ORIGIN, server);
|
||||||
|
CommandConfirmationPayload abortPayload = CommandConfirmationPayload
|
||||||
|
.builder()
|
||||||
|
.commandContext(model.getDriedCommandContext())
|
||||||
|
.otherButtonComponentId(model.getConfirmButtonId())
|
||||||
|
.action(CommandConfirmationPayload.CommandConfirmationAction.ABORT)
|
||||||
|
.build();
|
||||||
|
componentPayloadService.createButtonPayload(model.getAbortButtonId(), abortPayload, COMMAND_CONFIRMATION_ORIGIN, server);
|
||||||
|
scheduleConfirmationDeletion(createdMessage, model.getConfirmButtonId(), model.getAbortButtonId());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleConfirmationDeletion(Message createdMessage, String confirmationPayloadId, String abortPayloadId) {
|
||||||
|
HashMap<Object, Object> parameters = new HashMap<>();
|
||||||
|
Long serverId = createdMessage.getGuild().getIdLong();
|
||||||
|
parameters.put("serverId", serverId.toString());
|
||||||
|
parameters.put("channelId", createdMessage.getChannel().getId());
|
||||||
|
parameters.put("messageId", createdMessage.getId());
|
||||||
|
parameters.put("confirmationPayloadId", confirmationPayloadId);
|
||||||
|
parameters.put("abortPayloadId", abortPayloadId);
|
||||||
|
JobParameters jobParameters = JobParameters
|
||||||
|
.builder()
|
||||||
|
.parameters(parameters)
|
||||||
|
.build();
|
||||||
|
Long confirmationTimeout = configService.getLongValueOrConfigDefault(CoreFeatureConfig.CONFIRMATION_TIMEOUT, serverId);
|
||||||
|
Instant targetDate = Instant.now().plus(confirmationTimeout, ChronoUnit.SECONDS);
|
||||||
|
long channelId = createdMessage.getChannel().getIdLong();
|
||||||
|
log.info("Scheduling job to delete confirmation message {} in channel {} in server {} at {}.", createdMessage.getIdLong(), channelId, serverId, targetDate);
|
||||||
|
schedulerService.executeJobWithParametersOnce("confirmationCleanupJob", "core", jobParameters, Date.from(targetDate));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void executeCommand(MessageReceivedEvent event, Command foundCommand, Parameters parsedParameters) {
|
public void executeCommand(MessageReceivedEvent event, Command foundCommand, Parameters parsedParameters) {
|
||||||
UserInitiatedServerContext userInitiatedContext = buildTemplateParameter(event);
|
UserInitiatedServerContext userInitiatedContext = buildUserInitiatedServerContext(event);
|
||||||
CommandContext.CommandContextBuilder commandContextBuilder = CommandContext.builder()
|
CommandContext.CommandContextBuilder commandContextBuilder = CommandContext.builder()
|
||||||
.author(event.getMember())
|
.author(event.getMember())
|
||||||
.guild(event.getGuild())
|
.guild(event.getGuild())
|
||||||
@@ -153,9 +254,27 @@ public class CommandReceivedHandler extends ListenerAdapter {
|
|||||||
conditionResultFuture.thenAccept(conditionResult -> {
|
conditionResultFuture.thenAccept(conditionResult -> {
|
||||||
CommandResult commandResult = null;
|
CommandResult commandResult = null;
|
||||||
if(conditionResult.isResult()) {
|
if(conditionResult.isResult()) {
|
||||||
if(foundCommand.getConfiguration().isAsync()) {
|
CommandConfiguration commandConfiguration = foundCommand.getConfiguration();
|
||||||
|
if(commandConfiguration.isRequiresConfirmation()) {
|
||||||
|
DriedCommandContext driedCommandContext = DriedCommandContext.buildFromCommandContext(commandContext);
|
||||||
|
driedCommandContext.setCommandName(commandConfiguration.getName());
|
||||||
|
String confirmId = componentService.generateComponentId();
|
||||||
|
String abortId = componentService.generateComponentId();
|
||||||
|
CommandConfirmationModel model = CommandConfirmationModel
|
||||||
|
.builder()
|
||||||
|
.abortButtonId(abortId)
|
||||||
|
.confirmButtonId(confirmId)
|
||||||
|
.driedCommandContext(driedCommandContext)
|
||||||
|
.commandName(commandConfiguration.getName())
|
||||||
|
.build();
|
||||||
|
MessageToSend message = templateService.renderEmbedTemplate(COMMAND_CONFIRMATION_MESSAGE_TEMPLATE_KEY, model, event.getGuild().getIdLong());
|
||||||
|
List<CompletableFuture<Message>> confirmationMessageFutures = channelService.sendMessageToSendToChannel(message, event.getChannel());
|
||||||
|
FutureUtils.toSingleFutureGeneric(confirmationMessageFutures)
|
||||||
|
.thenAccept(unused -> self.persistConfirmationCallbacks(model, confirmationMessageFutures.get(0).join()))
|
||||||
|
.exceptionally(throwable -> self.failedCommandHandling(event, foundCommand, parsedParameters, commandContext, throwable));
|
||||||
|
} else if(commandConfiguration.isAsync()) {
|
||||||
log.info("Executing async command {} for server {} in channel {} based on message {} by user {}.",
|
log.info("Executing async command {} for server {} in channel {} based on message {} by user {}.",
|
||||||
foundCommand.getConfiguration().getName(), commandContext.getGuild().getId(), commandContext.getChannel().getId(), commandContext.getMessage().getId(), commandContext.getAuthor().getId());
|
commandConfiguration.getName(), commandContext.getGuild().getId(), commandContext.getChannel().getId(), commandContext.getMessage().getId(), commandContext.getAuthor().getId());
|
||||||
|
|
||||||
self.executeAsyncCommand(foundCommand, commandContext)
|
self.executeAsyncCommand(foundCommand, commandContext)
|
||||||
.exceptionally(throwable -> failedCommandHandling(event, foundCommand, parsedParameters, commandContext, throwable));
|
.exceptionally(throwable -> failedCommandHandling(event, foundCommand, parsedParameters, commandContext, throwable));
|
||||||
@@ -174,7 +293,7 @@ public class CommandReceivedHandler extends ListenerAdapter {
|
|||||||
|
|
||||||
private Void failedCommandHandling(MessageReceivedEvent event, Command foundCommand, Parameters parsedParameters, CommandContext commandContext, Throwable throwable) {
|
private Void failedCommandHandling(MessageReceivedEvent event, Command foundCommand, Parameters parsedParameters, CommandContext commandContext, Throwable throwable) {
|
||||||
log.error("Asynchronous command {} failed.", foundCommand.getConfiguration().getName(), throwable);
|
log.error("Asynchronous command {} failed.", foundCommand.getConfiguration().getName(), throwable);
|
||||||
UserInitiatedServerContext rebuildUserContext = buildTemplateParameter(event);
|
UserInitiatedServerContext rebuildUserContext = buildUserInitiatedServerContext(commandContext);
|
||||||
CommandContext rebuildContext = CommandContext.builder()
|
CommandContext rebuildContext = CommandContext.builder()
|
||||||
.author(event.getMember())
|
.author(event.getMember())
|
||||||
.guild(event.getGuild())
|
.guild(event.getGuild())
|
||||||
@@ -197,15 +316,20 @@ public class CommandReceivedHandler extends ListenerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void reportException(MessageReceivedEvent event, Command foundCommand, Throwable throwable, String s) {
|
public void reportException(CommandContext context, Command foundCommand, Throwable throwable, String s) {
|
||||||
UserInitiatedServerContext userInitiatedContext = buildTemplateParameter(event);
|
reportException(context.getMessage(), context.getChannel(), context.getAuthor(), foundCommand, throwable, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void reportException(Message message, TextChannel textChannel, Member member, Command foundCommand, Throwable throwable, String s) {
|
||||||
|
UserInitiatedServerContext userInitiatedContext = buildUserInitiatedServerContext(member, textChannel, member.getGuild());
|
||||||
CommandContext.CommandContextBuilder commandContextBuilder = CommandContext.builder()
|
CommandContext.CommandContextBuilder commandContextBuilder = CommandContext.builder()
|
||||||
.author(event.getMember())
|
.author(member)
|
||||||
.guild(event.getGuild())
|
.guild(message.getGuild())
|
||||||
.undoActions(new ArrayList<>())
|
.undoActions(new ArrayList<>())
|
||||||
.channel(event.getTextChannel())
|
.channel(message.getTextChannel())
|
||||||
.message(event.getMessage())
|
.message(message)
|
||||||
.jda(event.getJDA())
|
.jda(message.getJDA())
|
||||||
.userInitiatedContext(userInitiatedContext);
|
.userInitiatedContext(userInitiatedContext);
|
||||||
log.error(s, throwable);
|
log.error(s, throwable);
|
||||||
CommandResult commandResult = CommandResult.fromError(throwable.getMessage(), throwable);
|
CommandResult commandResult = CommandResult.fromError(throwable.getMessage(), throwable);
|
||||||
@@ -213,6 +337,11 @@ public class CommandReceivedHandler extends ListenerAdapter {
|
|||||||
self.executePostCommandListener(foundCommand, commandContext, commandResult);
|
self.executePostCommandListener(foundCommand, commandContext, commandResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void reportException(MessageReceivedEvent event, Command foundCommand, Throwable throwable, String s) {
|
||||||
|
reportException(event.getMessage(), event.getTextChannel(), event.getMember(), foundCommand, throwable, s);
|
||||||
|
}
|
||||||
|
|
||||||
private void validateCommandParameters(Parameters parameters, Command foundCommand) {
|
private void validateCommandParameters(Parameters parameters, Command foundCommand) {
|
||||||
CommandConfiguration commandConfiguration = foundCommand.getConfiguration();
|
CommandConfiguration commandConfiguration = foundCommand.getConfiguration();
|
||||||
List<Parameter> parameterList = commandConfiguration.getParameters();
|
List<Parameter> parameterList = commandConfiguration.getParameters();
|
||||||
@@ -249,15 +378,23 @@ public class CommandReceivedHandler extends ListenerAdapter {
|
|||||||
return foundCommand.execute(commandContext);
|
return foundCommand.execute(commandContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserInitiatedServerContext buildTemplateParameter(MessageReceivedEvent event) {
|
private UserInitiatedServerContext buildUserInitiatedServerContext(Member member, TextChannel textChannel, Guild guild) {
|
||||||
return UserInitiatedServerContext
|
return UserInitiatedServerContext
|
||||||
.builder()
|
.builder()
|
||||||
.member(event.getMember())
|
.member(member)
|
||||||
.messageChannel(event.getTextChannel())
|
.messageChannel(textChannel)
|
||||||
.guild(event.getGuild())
|
.guild(guild)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UserInitiatedServerContext buildUserInitiatedServerContext(MessageReceivedEvent event) {
|
||||||
|
return buildUserInitiatedServerContext(event.getMember(), event.getTextChannel(), event.getGuild());
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserInitiatedServerContext buildUserInitiatedServerContext(CommandContext context) {
|
||||||
|
return buildUserInitiatedServerContext(context.getAuthor(), context.getChannel(), context.getGuild());
|
||||||
|
}
|
||||||
|
|
||||||
public CompletableFuture<Parameters> getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message){
|
public CompletableFuture<Parameters> getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message){
|
||||||
List<ParseResult> parsedParameters = new ArrayList<>();
|
List<ParseResult> parsedParameters = new ArrayList<>();
|
||||||
List<Parameter> parameters = command.getConfiguration().getParameters();
|
List<Parameter> parameters = command.getConfiguration().getParameters();
|
||||||
@@ -405,4 +542,18 @@ public class CommandReceivedHandler extends ListenerAdapter {
|
|||||||
metricService.registerCounter(COMMANDS_WRONG_PARAMETER_COUNTER, "Commands with incorrect parameter");
|
metricService.registerCounter(COMMANDS_WRONG_PARAMETER_COUNTER, "Commands with incorrect parameter");
|
||||||
this.parameterHandlers = parameterHandlers.stream().sorted(comparing(CommandParameterHandler::getPriority)).collect(Collectors.toList());
|
this.parameterHandlers = parameterHandlers.stream().sorted(comparing(CommandParameterHandler::getPriority)).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
public static class CommandParseResult {
|
||||||
|
private Parameters parameters;
|
||||||
|
private Command command;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
public static class UnParsedCommandResult {
|
||||||
|
private UnParsedCommandParameter parameter;
|
||||||
|
private Command command;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package dev.sheldan.abstracto.core.command.listener;
|
||||||
|
|
||||||
|
import dev.sheldan.abstracto.core.command.CommandReceivedHandler;
|
||||||
|
import dev.sheldan.abstracto.core.command.config.features.CoreFeatureDefinition;
|
||||||
|
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||||
|
import dev.sheldan.abstracto.core.command.execution.DriedCommandContext;
|
||||||
|
import dev.sheldan.abstracto.core.command.model.CommandConfirmationPayload;
|
||||||
|
import dev.sheldan.abstracto.core.command.model.CommandServiceBean;
|
||||||
|
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||||
|
import dev.sheldan.abstracto.core.config.ListenerPriority;
|
||||||
|
import dev.sheldan.abstracto.core.interaction.InteractionService;
|
||||||
|
import dev.sheldan.abstracto.core.listener.ButtonClickedListenerResult;
|
||||||
|
import dev.sheldan.abstracto.core.listener.async.jda.ButtonClickedListener;
|
||||||
|
import dev.sheldan.abstracto.core.models.listener.ButtonClickedListenerModel;
|
||||||
|
import dev.sheldan.abstracto.core.service.MessageService;
|
||||||
|
import dev.sheldan.abstracto.core.service.management.ComponentPayloadManagementService;
|
||||||
|
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Slf4j
|
||||||
|
public class ConfirmationButtonClickedListener implements ButtonClickedListener {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CommandServiceBean commandServiceBean;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CommandReceivedHandler commandReceivedHandler;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MessageService messageService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ComponentPayloadManagementService componentPayloadManagementService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ConfirmationButtonClickedListener self;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private InteractionService interactionService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) {
|
||||||
|
CommandConfirmationPayload payload = (CommandConfirmationPayload) model.getDeserializedPayload();
|
||||||
|
DriedCommandContext commandCtx = payload.getCommandContext();
|
||||||
|
if(payload.getAction().equals(CommandConfirmationPayload.CommandConfirmationAction.CONFIRM)) {
|
||||||
|
log.info("Confirming command {} in server {} from message {} in channel {} with event {}.",
|
||||||
|
commandCtx.getCommandName(), commandCtx.getServerId(), commandCtx.getMessageId(),
|
||||||
|
commandCtx.getChannelId(), model.getEvent().getInteraction().getId());
|
||||||
|
commandServiceBean.fillCommandContext(commandCtx)
|
||||||
|
.thenAccept(context -> self.executeButtonClickedListener(model, payload, context))
|
||||||
|
.exceptionally(throwable -> {
|
||||||
|
log.error("Command confirmation failed to execute.", throwable);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
log.info("Denying command {} in server {} from message {} in channel {} with event {}.",
|
||||||
|
commandCtx.getCommandName(), commandCtx.getServerId(), commandCtx.getMessageId(),
|
||||||
|
commandCtx.getChannelId(), model.getEvent().getInteraction().getId());
|
||||||
|
cleanup(model, payload);
|
||||||
|
}
|
||||||
|
return ButtonClickedListenerResult.ACKNOWLEDGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void executeButtonClickedListener(ButtonClickedListenerModel model, CommandConfirmationPayload payload, CommandServiceBean.RebuiltCommandContext context) {
|
||||||
|
try {
|
||||||
|
if(context.getCommand().getConfiguration().isAsync()) {
|
||||||
|
commandReceivedHandler.executeAsyncCommand(context.getCommand(), context.getContext());
|
||||||
|
} else {
|
||||||
|
CommandResult result = commandReceivedHandler.executeCommand(context.getCommand(), context.getContext());
|
||||||
|
commandReceivedHandler.executePostCommandListener(context.getCommand(), context.getContext(), result);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
commandReceivedHandler.reportException(context.getContext(), context.getCommand(), e, "Confirmation execution of command failed.");
|
||||||
|
} finally {
|
||||||
|
cleanup(model, payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanup(ButtonClickedListenerModel model, CommandConfirmationPayload payload) {
|
||||||
|
log.debug("Cleaning up component {} and {}.", payload.getOtherButtonComponentId(), model.getEvent().getComponentId());
|
||||||
|
componentPayloadManagementService.deletePayloads(Arrays.asList(payload.getOtherButtonComponentId(), model.getEvent().getComponentId()));
|
||||||
|
log.debug("Deleting confirmation message {}.", model.getEvent().getMessageId());
|
||||||
|
messageService.deleteMessage(model.getEvent().getMessage())
|
||||||
|
.thenAccept(unused -> self.sendAbortNotification(model))
|
||||||
|
.exceptionally(throwable -> {
|
||||||
|
log.warn("Failed to clean up confirmation message {}.", model.getEvent().getMessageId());
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<Void> sendAbortNotification(ButtonClickedListenerModel model) {
|
||||||
|
log.info("Sending abort notification for message {}", model.getEvent().getMessageId());
|
||||||
|
return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction("command_aborted_notification", new Object(), model.getEvent().getHook()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean handlesEvent(ButtonClickedListenerModel model) {
|
||||||
|
return model.getOrigin().equals(CommandReceivedHandler.COMMAND_CONFIRMATION_ORIGIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FeatureDefinition getFeature() {
|
||||||
|
return CoreFeatureDefinition.CORE_FEATURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getPriority() {
|
||||||
|
return ListenerPriority.MEDIUM;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package dev.sheldan.abstracto.core.command.model;
|
||||||
|
|
||||||
|
import dev.sheldan.abstracto.core.command.execution.DriedCommandContext;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
public class CommandConfirmationModel {
|
||||||
|
private String confirmButtonId;
|
||||||
|
private String abortButtonId;
|
||||||
|
private DriedCommandContext driedCommandContext;
|
||||||
|
private String commandName;
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package dev.sheldan.abstracto.core.command.model;
|
||||||
|
|
||||||
|
import dev.sheldan.abstracto.core.command.execution.DriedCommandContext;
|
||||||
|
import dev.sheldan.abstracto.core.models.template.button.ButtonPayload;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Builder
|
||||||
|
@Setter
|
||||||
|
public class CommandConfirmationPayload implements ButtonPayload {
|
||||||
|
private DriedCommandContext commandContext;
|
||||||
|
private CommandConfirmationAction action;
|
||||||
|
private String otherButtonComponentId;
|
||||||
|
|
||||||
|
public enum CommandConfirmationAction {
|
||||||
|
CONFIRM, ABORT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package dev.sheldan.abstracto.core.command.service;
|
package dev.sheldan.abstracto.core.command.model;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import dev.sheldan.abstracto.core.command.Command;
|
import dev.sheldan.abstracto.core.command.Command;
|
||||||
@@ -10,20 +10,29 @@ import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
|||||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||||
import dev.sheldan.abstracto.core.command.config.Parameters;
|
import dev.sheldan.abstracto.core.command.config.Parameters;
|
||||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||||
|
import dev.sheldan.abstracto.core.command.execution.DriedCommandContext;
|
||||||
import dev.sheldan.abstracto.core.command.execution.UnParsedCommandParameter;
|
import dev.sheldan.abstracto.core.command.execution.UnParsedCommandParameter;
|
||||||
import dev.sheldan.abstracto.core.command.model.database.ACommand;
|
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.ACommandInAServer;
|
||||||
import dev.sheldan.abstracto.core.command.model.database.AModule;
|
import dev.sheldan.abstracto.core.command.model.database.AModule;
|
||||||
|
import dev.sheldan.abstracto.core.command.service.CommandRegistry;
|
||||||
|
import dev.sheldan.abstracto.core.command.service.CommandService;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.ModuleManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.ModuleManagementService;
|
||||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||||
|
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
|
||||||
import dev.sheldan.abstracto.core.models.database.AFeature;
|
import dev.sheldan.abstracto.core.models.database.AFeature;
|
||||||
import dev.sheldan.abstracto.core.models.database.ARole;
|
import dev.sheldan.abstracto.core.models.database.ARole;
|
||||||
import dev.sheldan.abstracto.core.models.database.AServer;
|
import dev.sheldan.abstracto.core.models.database.AServer;
|
||||||
|
import dev.sheldan.abstracto.core.service.MemberService;
|
||||||
|
import dev.sheldan.abstracto.core.service.MessageService;
|
||||||
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.dv8tion.jda.api.entities.Member;
|
||||||
import net.dv8tion.jda.api.entities.Message;
|
import net.dv8tion.jda.api.entities.Message;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -59,6 +68,12 @@ public class CommandServiceBean implements CommandService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private CommandReceivedHandler commandReceivedHandler;
|
private CommandReceivedHandler commandReceivedHandler;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MemberService memberService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MessageService messageService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ACommand createCommand(String name, String moduleName, FeatureDefinition featureDefinition) {
|
public ACommand createCommand(String name, String moduleName, FeatureDefinition featureDefinition) {
|
||||||
AModule module = moduleManagementService.getOrCreate(moduleName);
|
AModule module = moduleManagementService.getOrCreate(moduleName);
|
||||||
@@ -216,5 +231,46 @@ public class CommandServiceBean implements CommandService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CompletableFuture<RebuiltCommandContext> fillCommandContext(DriedCommandContext commandContext) {
|
||||||
|
CompletableFuture<Member> memberFuture = memberService.getMemberInServerAsync(commandContext.getServerId(), commandContext.getUserId());
|
||||||
|
CompletableFuture<Message> messageFuture = messageService.loadMessage(commandContext.getServerId(), commandContext.getChannelId(), commandContext.getMessageId());
|
||||||
|
return CompletableFuture.allOf(memberFuture, messageFuture).thenCompose(unused -> {
|
||||||
|
Message message = messageFuture.join();
|
||||||
|
CommandReceivedHandler.UnParsedCommandResult unparsedResult = commandReceivedHandler.getUnparsedCommandResult(message);
|
||||||
|
CompletableFuture<CommandReceivedHandler.CommandParseResult> getParseResult = commandReceivedHandler.getParametersFromMessage(message, unparsedResult);
|
||||||
|
return getParseResult.thenApply(commandParseResult -> {
|
||||||
|
Member author = memberFuture.join();
|
||||||
|
UserInitiatedServerContext userInitiatedServerContext = UserInitiatedServerContext
|
||||||
|
.builder()
|
||||||
|
.messageChannel(message.getChannel())
|
||||||
|
.message(message)
|
||||||
|
.guild(message.getGuild())
|
||||||
|
.build();
|
||||||
|
CommandContext context = CommandContext
|
||||||
|
.builder()
|
||||||
|
.channel(message.getTextChannel())
|
||||||
|
.author(author)
|
||||||
|
.guild(message.getGuild())
|
||||||
|
.jda(message.getJDA())
|
||||||
|
.parameters(commandParseResult.getParameters())
|
||||||
|
.userInitiatedContext(userInitiatedServerContext)
|
||||||
|
.message(message)
|
||||||
|
.build();
|
||||||
|
return RebuiltCommandContext
|
||||||
|
.builder()
|
||||||
|
.context(context)
|
||||||
|
.command(unparsedResult.getCommand())
|
||||||
|
.build();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Getter
|
||||||
|
public static class RebuiltCommandContext {
|
||||||
|
private CommandContext context;
|
||||||
|
private Command command;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -39,6 +39,7 @@ public class DeleteAlias extends AbstractConditionableCommand {
|
|||||||
.module(ConfigModuleDefinition.CONFIG)
|
.module(ConfigModuleDefinition.CONFIG)
|
||||||
.parameters(parameters)
|
.parameters(parameters)
|
||||||
.templated(true)
|
.templated(true)
|
||||||
|
.requiresConfirmation(true)
|
||||||
.supportsEmbedException(true)
|
.supportsEmbedException(true)
|
||||||
.help(helpInfo)
|
.help(helpInfo)
|
||||||
.causesReaction(true)
|
.causesReaction(true)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
|||||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
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.ACommand;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandService;
|
import dev.sheldan.abstracto.core.command.service.CommandService;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
|
import dev.sheldan.abstracto.core.command.model.CommandServiceBean;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
||||||
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
|||||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
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.ACommand;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandService;
|
import dev.sheldan.abstracto.core.command.service.CommandService;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
|
import dev.sheldan.abstracto.core.command.model.CommandServiceBean;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
||||||
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
|||||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
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.ACommand;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandService;
|
import dev.sheldan.abstracto.core.command.service.CommandService;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
|
import dev.sheldan.abstracto.core.command.model.CommandServiceBean;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
||||||
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
|||||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
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.ACommand;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandService;
|
import dev.sheldan.abstracto.core.command.service.CommandService;
|
||||||
import dev.sheldan.abstracto.core.command.service.CommandServiceBean;
|
import dev.sheldan.abstracto.core.command.model.CommandServiceBean;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.FeatureManagementService;
|
||||||
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
import dev.sheldan.abstracto.core.commands.config.ConfigModuleDefinition;
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package dev.sheldan.abstracto.core.job;
|
||||||
|
|
||||||
|
import dev.sheldan.abstracto.core.command.CommandReceivedHandler;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.quartz.DisallowConcurrentExecution;
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
import org.quartz.PersistJobDataAfterExecution;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@DisallowConcurrentExecution
|
||||||
|
@Component
|
||||||
|
@PersistJobDataAfterExecution
|
||||||
|
@Setter
|
||||||
|
public class ConfirmationCleanupJob extends QuartzJobBean {
|
||||||
|
|
||||||
|
private Long serverId;
|
||||||
|
private Long channelId;
|
||||||
|
private Long messageId;
|
||||||
|
private String confirmationPayloadId;
|
||||||
|
private String abortPayloadId;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private CommandReceivedHandler commandReceivedHandler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||||
|
log.info("Cleaning up confirmation message {} in server {} in channel {}.", messageId, serverId, channelId);
|
||||||
|
commandReceivedHandler.cleanupConfirmationMessage(serverId, channelId, messageId, confirmationPayloadId, abortPayloadId)
|
||||||
|
.thenAccept(unused -> log.info("Deleted confirmation message {}", messageId))
|
||||||
|
.exceptionally(throwable -> {
|
||||||
|
log.warn("Failed to cleanup confirmation message {}.", messageId);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,7 @@ public class ComponentPayloadManagementServiceBean implements ComponentPayloadMa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deletePayloads(List<String> ids) {
|
public void deletePayloads(List<String> ids) {
|
||||||
|
ids.forEach(payloadId -> log.info("Deleting payload {}", payloadId));
|
||||||
repository.deleteByIdIn(ids);
|
repository.deleteByIdIn(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ abstracto.systemConfigs.prefix.stringValue=!
|
|||||||
abstracto.systemConfigs.noCommandFoundReporting.name=noCommandFoundReporting
|
abstracto.systemConfigs.noCommandFoundReporting.name=noCommandFoundReporting
|
||||||
abstracto.systemConfigs.noCommandFoundReporting.stringValue=true
|
abstracto.systemConfigs.noCommandFoundReporting.stringValue=true
|
||||||
|
|
||||||
|
abstracto.systemConfigs.confirmationTimeout.name=confirmationTimeout
|
||||||
|
abstracto.systemConfigs.confirmationTimeout.longValue=120
|
||||||
|
|
||||||
abstracto.systemConfigs.maxMessages.name=maxMessages
|
abstracto.systemConfigs.maxMessages.name=maxMessages
|
||||||
abstracto.systemConfigs.maxMessages.longValue=3
|
abstracto.systemConfigs.maxMessages.longValue=3
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||||
|
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||||
|
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||||
|
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd">
|
||||||
|
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
|
||||||
|
</databaseChangeLog>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||||
|
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||||
|
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||||
|
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||||
|
<changeSet author="Sheldan" id="confirmation-cleanup-job-insert">
|
||||||
|
<insert tableName="scheduler_job">
|
||||||
|
<column name="name" value="confirmationCleanupJob"/>
|
||||||
|
<column name="group_name" value="core"/>
|
||||||
|
<column name="clazz" value="dev.sheldan.abstracto.core.job.ConfirmationCleanupJob"/>
|
||||||
|
<column name="active" value="true"/>
|
||||||
|
<column name="recovery" value="false"/>
|
||||||
|
</insert>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||||
|
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
|
||||||
|
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
|
||||||
|
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
|
||||||
|
<include file="confirmationCleanupJob.xml" relativeToChangelogFile="true"/>
|
||||||
|
</databaseChangeLog>
|
||||||
@@ -20,4 +20,5 @@
|
|||||||
<include file="1.3.1/collection.xml" relativeToChangelogFile="true"/>
|
<include file="1.3.1/collection.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="1.3.5/collection.xml" relativeToChangelogFile="true"/>
|
<include file="1.3.5/collection.xml" relativeToChangelogFile="true"/>
|
||||||
<include file="1.3.6/collection.xml" relativeToChangelogFile="true"/>
|
<include file="1.3.6/collection.xml" relativeToChangelogFile="true"/>
|
||||||
|
<include file="1.3.9/collection.xml" relativeToChangelogFile="true"/>
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
@@ -122,6 +122,9 @@ public class CommandReceivedHandlerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private List<Member> members;
|
private List<Member> members;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Member member;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private Bag<Role> roles;
|
private Bag<Role> roles;
|
||||||
|
|
||||||
@@ -161,6 +164,8 @@ public class CommandReceivedHandlerTest {
|
|||||||
when(commandManager.isCommand(message)).thenReturn(true);
|
when(commandManager.isCommand(message)).thenReturn(true);
|
||||||
when(event.getGuild()).thenReturn(guild);
|
when(event.getGuild()).thenReturn(guild);
|
||||||
when(event.getChannel()).thenReturn(channel);
|
when(event.getChannel()).thenReturn(channel);
|
||||||
|
when(event.getMember()).thenReturn(member);
|
||||||
|
when(message.getGuild()).thenReturn(guild);
|
||||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||||
when(message.getContentRaw()).thenReturn(MESSAGE_CONTENT_COMMAND_ONLY);
|
when(message.getContentRaw()).thenReturn(MESSAGE_CONTENT_COMMAND_ONLY);
|
||||||
when(commandManager.getCommandName(anyString(), eq(SERVER_ID))).thenReturn(COMMAND_NAME);
|
when(commandManager.getCommandName(anyString(), eq(SERVER_ID))).thenReturn(COMMAND_NAME);
|
||||||
@@ -286,9 +291,9 @@ public class CommandReceivedHandlerTest {
|
|||||||
parameterHandlers.add(parameterHandler);
|
parameterHandlers.add(parameterHandler);
|
||||||
parameterHandlers.add(secondParameterHandler);
|
parameterHandlers.add(secondParameterHandler);
|
||||||
when(event.isFromGuild()).thenReturn(true);
|
when(event.isFromGuild()).thenReturn(true);
|
||||||
|
when(message.getGuild()).thenReturn(guild);
|
||||||
when(event.getMessage()).thenReturn(message);
|
when(event.getMessage()).thenReturn(message);
|
||||||
when(commandManager.isCommand(message)).thenReturn(true);
|
when(commandManager.isCommand(message)).thenReturn(true);
|
||||||
when(event.getGuild()).thenReturn(guild);
|
|
||||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||||
when(message.getContentRaw()).thenReturn(messageContentTwoParameter);
|
when(message.getContentRaw()).thenReturn(messageContentTwoParameter);
|
||||||
when(commandManager.getCommandName(anyString(), eq(SERVER_ID))).thenReturn(COMMAND_NAME);
|
when(commandManager.getCommandName(anyString(), eq(SERVER_ID))).thenReturn(COMMAND_NAME);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.core.command.service;
|
|||||||
import dev.sheldan.abstracto.core.command.Command;
|
import dev.sheldan.abstracto.core.command.Command;
|
||||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||||
|
import dev.sheldan.abstracto.core.command.model.CommandServiceBean;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import dev.sheldan.abstracto.core.command.config.EffectConfig;
|
|||||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.CommandInServerManagementService;
|
||||||
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
|
||||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
|
||||||
import dev.sheldan.abstracto.core.models.database.RoleImmunity;
|
import dev.sheldan.abstracto.core.models.database.RoleImmunity;
|
||||||
import dev.sheldan.abstracto.core.service.RoleImmunityService;
|
import dev.sheldan.abstracto.core.service.RoleImmunityService;
|
||||||
import dev.sheldan.abstracto.core.service.RoleService;
|
import dev.sheldan.abstracto.core.service.RoleService;
|
||||||
@@ -113,7 +112,6 @@ public class ImmuneUserCondition implements CommandCondition {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resultFuture.completeExceptionally(new AbstractoRunTimeException("No member found for given member in condition."));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ public class CommandConfiguration {
|
|||||||
@Builder.Default
|
@Builder.Default
|
||||||
private boolean supportsEmbedException = false;
|
private boolean supportsEmbedException = false;
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private boolean requiresConfirmation = false;
|
||||||
|
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private List<Parameter> parameters = new ArrayList<>();
|
private List<Parameter> parameters = new ArrayList<>();
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public class CoreFeatureConfig implements FeatureConfig {
|
|||||||
public static final String SUCCESS_REACTION_KEY = "successReaction";
|
public static final String SUCCESS_REACTION_KEY = "successReaction";
|
||||||
public static final String WARN_REACTION_KEY = "warnReaction";
|
public static final String WARN_REACTION_KEY = "warnReaction";
|
||||||
public static final String MAX_MESSAGES_KEY = "maxMessages";
|
public static final String MAX_MESSAGES_KEY = "maxMessages";
|
||||||
|
public static final String CONFIRMATION_TIMEOUT = "confirmationTimeout";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FeatureDefinition getFeature() {
|
public FeatureDefinition getFeature() {
|
||||||
@@ -27,6 +28,6 @@ public class CoreFeatureConfig implements FeatureConfig {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getRequiredSystemConfigKeys() {
|
public List<String> getRequiredSystemConfigKeys() {
|
||||||
return Arrays.asList(NO_COMMAND_REPORTING_CONFIG_KEY, MAX_MESSAGES_KEY);
|
return Arrays.asList(NO_COMMAND_REPORTING_CONFIG_KEY, MAX_MESSAGES_KEY, CONFIRMATION_TIMEOUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package dev.sheldan.abstracto.core.command.execution;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@Builder
|
||||||
|
public class DriedCommandContext {
|
||||||
|
private String commandName;
|
||||||
|
private Long serverId;
|
||||||
|
private Long channelId;
|
||||||
|
private Long messageId;
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
public static DriedCommandContext buildFromCommandContext(CommandContext commandContext) {
|
||||||
|
return DriedCommandContext
|
||||||
|
.builder()
|
||||||
|
.channelId(commandContext.getChannel().getIdLong())
|
||||||
|
.messageId(commandContext.getMessage().getIdLong())
|
||||||
|
.serverId(commandContext.getGuild().getIdLong())
|
||||||
|
.userId(commandContext.getMessage().getAuthor().getIdLong())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,7 +51,7 @@ Change configuration of ARP::
|
|||||||
|
|
||||||
Delete an ARP::
|
Delete an ARP::
|
||||||
* Usage: `deleteAssignableRolePlace <name>`
|
* Usage: `deleteAssignableRolePlace <name>`
|
||||||
* Description: Completely deletes the ARP identified by `name`. This includes any trace in the database and the current message, if any.
|
* Description: Completely deletes the ARP identified by `name`. This includes any trace in the database and the current message, if any. Requires you to confirm the command.
|
||||||
|
|
||||||
Change description text of ARP::
|
Change description text of ARP::
|
||||||
* Usage `editAssignableRolePlaceText <name> <newText>`
|
* Usage `editAssignableRolePlaceText <name> <newText>`
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
The core feature contains necessary commands in order for Abstracto to function and be configured.
|
The core feature contains necessary commands in order for Abstracto to function and be configured.
|
||||||
|
|
||||||
|
==== Relevant system configuration
|
||||||
|
`noCommandFoundReporting` Whether not found commands should be reported back to the user. Default: true.
|
||||||
|
|
||||||
|
`maxMessages` The upper limit of messages created by the template mechanism. Default: 3.
|
||||||
|
|
||||||
|
`confirmationTimeout` The duration in seconds after which the confirmation is deleted. Default: 120.
|
||||||
|
|
||||||
==== Emotes
|
==== Emotes
|
||||||
* `successReaction` reaction emote in case the command completed successfully
|
* `successReaction` reaction emote in case the command completed successfully
|
||||||
* `warnReaction` reaction emote in case the command did not complete successfully
|
* `warnReaction` reaction emote in case the command did not complete successfully
|
||||||
@@ -152,7 +159,7 @@ Create a server specific alias::
|
|||||||
* Description: Creates the server specific alias for command `commandName` identified by `alias`. This means that from now on, users can use the command identified by `commandName` by using `alias` in its place, when executing the command or when using the help command. This alias is only available in this server, and it is not allowed to use the names of existing commands or built-in aliases.
|
* Description: Creates the server specific alias for command `commandName` identified by `alias`. This means that from now on, users can use the command identified by `commandName` by using `alias` in its place, when executing the command or when using the help command. This alias is only available in this server, and it is not allowed to use the names of existing commands or built-in aliases.
|
||||||
Delete a server specific alias::
|
Delete a server specific alias::
|
||||||
* Usage: `deleteAlias <alias>`
|
* Usage: `deleteAlias <alias>`
|
||||||
* Description: Deletes the server specific alias identified by `alias`. It is not possible to delete built-in aliases.
|
* Description: Deletes the server specific alias identified by `alias`. It is not possible to delete built-in aliases. Requires you to confirm the command.
|
||||||
Creating a profanity group::
|
Creating a profanity group::
|
||||||
* Usage: `createProfanityGroup <profanityGroupName>`
|
* Usage: `createProfanityGroup <profanityGroupName>`
|
||||||
* Description: Creates a profanity group with the given `profanityGroupName`. This name must be unique within the server.
|
* Description: Creates a profanity group with the given `profanityGroupName`. This name must be unique within the server.
|
||||||
|
|||||||
@@ -31,18 +31,18 @@ Setting a role to be awarded at a certain level::
|
|||||||
* Usage: `setExpRole <level> <role>`
|
* Usage: `setExpRole <level> <role>`
|
||||||
* Description: Sets `role` to be awarded at the given `level`. If the role was previously assigned,
|
* Description: Sets `role` to be awarded at the given `level`. If the role was previously assigned,
|
||||||
this will cause to remove this assignment and recalculate the roles for all users previously having this role.
|
this will cause to remove this assignment and recalculate the roles for all users previously having this role.
|
||||||
A status image indicating the progress will be shown. It will not award this role to users which qualify for this, a `syncRoles` is necessary for this.
|
A status image indicating the progress will be shown. It will not award this role to users which qualify for this, a `syncRoles` is necessary for this. Requires you to confirm the command.
|
||||||
* Example: `setExpRole 50 @HighLevel` in order to award the role `HighLevel` at level `50` (the @HighLevel is a role mention)
|
* Example: `setExpRole 50 @HighLevel` in order to award the role `HighLevel` at level `50` (the @HighLevel is a role mention)
|
||||||
|
|
||||||
Syncing the roles of the members with the configuration::
|
Syncing the roles of the members with the configuration::
|
||||||
* Usage: `syncRoles`
|
* Usage: `syncRoles`
|
||||||
* Description: Recalculates the appropriate levels for all users on the server and awards the roles appropriate for the level.
|
* Description: Recalculates the appropriate levels for all users on the server and awards the roles appropriate for the level.
|
||||||
There will be a message indicating the current status of the progress, and it is highly advised to not execute this command while another instance is still processing.
|
There will be a message indicating the current status of the progress, and it is highly advised to not execute this command while another instance is still processing. Requires you to confirm the command.
|
||||||
This command can run for a longer period of time, depending on the amount of members in the guild.
|
This command can run for a longer period of time, depending on the amount of members in the guild.
|
||||||
|
|
||||||
Remove a role from being awarded at a certain level::
|
Remove a role from being awarded at a certain level::
|
||||||
* Usage: `unSetExpRole <role>`
|
* Usage: `unSetExpRole <role>`
|
||||||
* Description: Removes this role from the experience tracking, removes the role from all members previously owning it and recalculates their new role according to the configuration.
|
* Description: Removes this role from the experience tracking, removes the role from all members previously owning it and recalculates their new role according to the configuration. Requires you to confirm the command.
|
||||||
This will provide a status update message displaying the process.
|
This will provide a status update message displaying the process.
|
||||||
|
|
||||||
Disable experience gain for a certain role::
|
Disable experience gain for a certain role::
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ Showing your warnings::
|
|||||||
* Description: Displays the amount of warnings of the user executing on the server. This will show both active and total warnings.
|
* Description: Displays the amount of warnings of the user executing on the server. This will show both active and total warnings.
|
||||||
Decaying all warnings regardless of the date::
|
Decaying all warnings regardless of the date::
|
||||||
* Usage: `decayAllWarnings`
|
* Usage: `decayAllWarnings`
|
||||||
* Description: This will cause all warnings of this server which are not decayed yet to be decayed instantly.
|
* Description: This will cause all warnings of this server which are not decayed yet to be decayed instantly. Requires you to confirm the command.
|
||||||
Deleting a warning::
|
Deleting a warning::
|
||||||
* Usage: `deleteWarning <warnId>`
|
* Usage: `deleteWarning <warnId>`
|
||||||
* Description: Deletes the warning identified by `warnId` completely from the database.
|
* Description: Deletes the warning identified by `warnId` completely from the database.
|
||||||
@@ -91,7 +91,7 @@ Feature key: `warnDecay`
|
|||||||
==== Commands
|
==== Commands
|
||||||
Decaying all warnings if necessary::
|
Decaying all warnings if necessary::
|
||||||
* Usage: `decayWarnings`
|
* Usage: `decayWarnings`
|
||||||
* Description: Triggers the decay of the warnings instantly, which means, every not decayed warning on this server older than the configured amount of days will be decayed and the decay will be logged.
|
* Description: Triggers the decay of the warnings instantly, which means, every not decayed warning on this server older than the configured amount of days will be decayed and the decay will be logged. Requires you to confirm the command.
|
||||||
|
|
||||||
=== Muting
|
=== Muting
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ Showing the tracked filtered invites::
|
|||||||
|
|
||||||
Remove all or individual invites from the tracked filtered invites::
|
Remove all or individual invites from the tracked filtered invites::
|
||||||
* Usage: `removeTrackedInviteLinks [invite]`
|
* Usage: `removeTrackedInviteLinks [invite]`
|
||||||
* Description: Removes the stored statistic for the given `invite`. In case `invite` is not given, it will delete all tracked filtered invites from the server.
|
* Description: Removes the stored statistic for the given `invite`. In case `invite` is not given, it will delete all tracked filtered invites from the server. Requires you to confirm the command.
|
||||||
* Mode Restriction: This command is only available when the feature mode `trackUses` is enabled.
|
* Mode Restriction: This command is only available when the feature mode `trackUses` is enabled.
|
||||||
|
|
||||||
=== Profanity filter
|
=== Profanity filter
|
||||||
|
|||||||
@@ -43,13 +43,13 @@ Synchronize the server emotes with the database::
|
|||||||
A message containing the amount of emotes deleted and created is shown. If the feature mode `emoteAutoTrack` is enabled, this should only be necessary in case the bot had an outage.
|
A message containing the amount of emotes deleted and created is shown. If the feature mode `emoteAutoTrack` is enabled, this should only be necessary in case the bot had an outage.
|
||||||
Delete emote usages::
|
Delete emote usages::
|
||||||
* Usage: `purgeEmoteStats <emote> [period]`
|
* Usage: `purgeEmoteStats <emote> [period]`
|
||||||
* Description: This command removes any stored usages of `emote`. The `emote` can either be a valid usage or the ID of an emote. If `period` is given, only usages within this time period will be deleted, if it is not provided, the complete timeline will be deleted.
|
* Description: This command removes any stored usages of `emote`. The `emote` can either be a valid usage or the ID of an emote. If `period` is given, only usages within this time period will be deleted, if it is not provided, the complete timeline will be deleted. Requires you to confirm the command.
|
||||||
Deleting an individual tracked emote::
|
Deleting an individual tracked emote::
|
||||||
* Usage: `deleteTrackedEmote <emote>`
|
* Usage: `deleteTrackedEmote <emote>`
|
||||||
* Description: Deletes the tracked emote from the database including the usages. The `emote` can either be a valid usage or the ID of an emote.
|
* Description: Deletes the tracked emote from the database including the usages. The `emote` can either be a valid usage or the ID of an emote. Requires you to confirm the command.
|
||||||
Reset emote statistics::
|
Reset emote statistics::
|
||||||
* Usage: `resetEmoteStats`
|
* Usage: `resetEmoteStats`
|
||||||
* Description: This will delete all emote usages and tracked emotes in the database.
|
* Description: This will delete all emote usages and tracked emotes in the database. Requires you to confirm the command.
|
||||||
Show the image of external tracked emotes::
|
Show the image of external tracked emotes::
|
||||||
* Usage: `showExternalTrackedEmote <emote>`
|
* Usage: `showExternalTrackedEmote <emote>`
|
||||||
* Description: Shows the ID, name, link to the image and the image directly for `emote` in an embed.
|
* Description: Shows the ID, name, link to the image and the image directly for `emote` in an embed.
|
||||||
|
|||||||
@@ -164,11 +164,11 @@ Feature key: `repostDetection`
|
|||||||
==== Commands
|
==== Commands
|
||||||
Remove stored image posts and reposts of whole server or specific member::
|
Remove stored image posts and reposts of whole server or specific member::
|
||||||
* Usage: `purgeImagePosts [member]`
|
* Usage: `purgeImagePosts [member]`
|
||||||
* Description: If `member` is provided, this will delete all stored image hashes (and their reposts) from the database. If `member` is not provided, this will delete all stored image hashes (and their reposts) from the whole server.
|
* Description: If `member` is provided, this will delete all stored image hashes (and their reposts) from the database. If `member` is not provided, this will delete all stored image hashes (and their reposts) from the whole server. Requires you to confirm the command.
|
||||||
|
|
||||||
Remove reposts of whole server or specific member::
|
Remove reposts of whole server or specific member::
|
||||||
* Usage: `purgeReposts [member]`
|
* Usage: `purgeReposts [member]`
|
||||||
* Description: If `member` is provided, this will delete all reposts of the given member. If `member` is not provided, this will delete all reposts in the whole server.
|
* Description: If `member` is provided, this will delete all reposts of the given member. If `member` is not provided, this will delete all reposts in the whole server. Requires you to confirm the command.
|
||||||
|
|
||||||
Show the leaderboard of reposts::
|
Show the leaderboard of reposts::
|
||||||
* Usage: `repostLeaderboard [page]`
|
* Usage: `repostLeaderboard [page]`
|
||||||
|
|||||||
Reference in New Issue
Block a user