mirror of
https://github.com/Sheldan/abstracto.git
synced 2026-03-21 12:52:05 +00:00
[AB-242] refactoring suggestions
adding veto and unsuggest command adding support for configuration whether or not a reply mentions the message adding support to reply to a message via template changed default mention config to exclude role mentions
This commit is contained in:
@@ -504,7 +504,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
|
||||
CompletableFuture<Message> future = messageService.sendMessageToSendToUser(targetMember.getUser(), messageToSend);
|
||||
CompletableFuture<Message> sameThreadMessageFuture;
|
||||
if(featureModeService.featureModeActive(ModMailFeatureDefinition.MOD_MAIL, modMailThread.getServer(), ModMailMode.SEPARATE_MESSAGE)) {
|
||||
sameThreadMessageFuture = channelService.sendMessageToSendToAChannel(messageToSend, modMailThread.getChannel()).get(0);
|
||||
sameThreadMessageFuture = channelService.sendMessageEmbedToSendToAChannel(messageToSend, modMailThread.getChannel()).get(0);
|
||||
} else {
|
||||
sameThreadMessageFuture = CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
@@ -51,6 +51,12 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>dev.sheldan.abstracto.scheduling</groupId>
|
||||
<artifactId>scheduling-int</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -9,10 +9,8 @@ import dev.sheldan.abstracto.core.command.config.ParameterValidator;
|
||||
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
||||
import dev.sheldan.abstracto.suggestion.service.SuggestionService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -36,8 +34,7 @@ public class Accept extends AbstractConditionableCommand {
|
||||
Long suggestionId = (Long) parameters.get(0);
|
||||
String text = parameters.size() == 2 ? (String) parameters.get(1) : "";
|
||||
log.debug("Using default reason for accept: {}.", parameters.size() != 2);
|
||||
SuggestionLog suggestionModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class);
|
||||
return suggestionService.acceptSuggestion(suggestionId, text, suggestionModel)
|
||||
return suggestionService.acceptSuggestion(suggestionId, commandContext.getMessage(), text)
|
||||
.thenApply(aVoid -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,8 @@ import dev.sheldan.abstracto.core.command.config.ParameterValidator;
|
||||
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
||||
import dev.sheldan.abstracto.suggestion.service.SuggestionService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -36,8 +34,7 @@ public class Reject extends AbstractConditionableCommand {
|
||||
Long suggestionId = (Long) parameters.get(0);
|
||||
String text = parameters.size() == 2 ? (String) parameters.get(1) : "";
|
||||
log.debug("Using default reason for accept: {}.", parameters.size() != 2);
|
||||
SuggestionLog suggestionModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class);
|
||||
return suggestionService.rejectSuggestion(suggestionId, text, suggestionModel)
|
||||
return suggestionService.rejectSuggestion(suggestionId, commandContext.getMessage(), text)
|
||||
.thenApply(aVoid -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,8 @@ import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.command.execution.ContextConverter;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
||||
import dev.sheldan.abstracto.suggestion.service.SuggestionService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -29,9 +27,7 @@ public class Suggest extends AbstractConditionableCommand {
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
String text = (String) parameters.get(0);
|
||||
SuggestionLog suggestLogModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class);
|
||||
suggestLogModel.setSuggester(commandContext.getAuthor());
|
||||
return suggestionService.createSuggestionMessage(commandContext.getAuthor(), text, suggestLogModel)
|
||||
return suggestionService.createSuggestionMessage(commandContext.getMessage(), text)
|
||||
.thenApply(aVoid -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package dev.sheldan.abstracto.suggestion.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.config.ParameterValidator;
|
||||
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.service.SuggestionService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
public class UnSuggest extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private SuggestionService suggestionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
Long suggestionId = (Long) parameters.get(0);
|
||||
return suggestionService.removeSuggestion(suggestionId, commandContext.getAuthor())
|
||||
.thenApply(aVoid -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
List<ParameterValidator> suggestionIdValidator = Arrays.asList(MinIntegerValueValidator.min(1L));
|
||||
parameters.add(Parameter.builder().name("suggestionId").validators(suggestionIdValidator).type(Long.class).templated(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("unSuggest")
|
||||
.module(UtilityModuleDefinition.UTILITY)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return SuggestionFeatureDefinition.SUGGEST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package dev.sheldan.abstracto.suggestion.command;
|
||||
|
||||
import dev.sheldan.abstracto.core.command.UtilityModuleDefinition;
|
||||
import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand;
|
||||
import dev.sheldan.abstracto.core.command.config.CommandConfiguration;
|
||||
import dev.sheldan.abstracto.core.command.config.HelpInfo;
|
||||
import dev.sheldan.abstracto.core.command.config.Parameter;
|
||||
import dev.sheldan.abstracto.core.command.config.ParameterValidator;
|
||||
import dev.sheldan.abstracto.core.command.config.validator.MinIntegerValueValidator;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandContext;
|
||||
import dev.sheldan.abstracto.core.command.execution.CommandResult;
|
||||
import dev.sheldan.abstracto.core.config.FeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition;
|
||||
import dev.sheldan.abstracto.suggestion.service.SuggestionService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class Veto extends AbstractConditionableCommand {
|
||||
|
||||
@Autowired
|
||||
private SuggestionService suggestionService;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
|
||||
List<Object> parameters = commandContext.getParameters().getParameters();
|
||||
Long suggestionId = (Long) parameters.get(0);
|
||||
String text = parameters.size() == 2 ? (String) parameters.get(1) : "";
|
||||
log.debug("Using default reason for veto: {}.", parameters.size() != 2);
|
||||
return suggestionService.vetoSuggestion(suggestionId, commandContext.getMessage(), text)
|
||||
.thenApply(aVoid -> CommandResult.fromSuccess());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandConfiguration getConfiguration() {
|
||||
List<Parameter> parameters = new ArrayList<>();
|
||||
|
||||
List<ParameterValidator> suggestionIdValidator = Arrays.asList(MinIntegerValueValidator.min(1L));
|
||||
parameters.add(Parameter.builder().name("suggestionId").validators(suggestionIdValidator).type(Long.class).templated(true).build());
|
||||
parameters.add(Parameter.builder().name("text").type(String.class).optional(true).remainder(true).templated(true).build());
|
||||
HelpInfo helpInfo = HelpInfo.builder().templated(true).hasExample(true).build();
|
||||
return CommandConfiguration.builder()
|
||||
.name("veto")
|
||||
.module(UtilityModuleDefinition.UTILITY)
|
||||
.templated(true)
|
||||
.async(true)
|
||||
.supportsEmbedException(true)
|
||||
.causesReaction(true)
|
||||
.parameters(parameters)
|
||||
.help(helpInfo)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeatureDefinition getFeature() {
|
||||
return SuggestionFeatureDefinition.SUGGEST;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package dev.sheldan.abstracto.suggestion.job;
|
||||
|
||||
import dev.sheldan.abstracto.suggestion.service.SuggestionService;
|
||||
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
|
||||
public class SuggestionCleanUpJob extends QuartzJobBean {
|
||||
|
||||
@Autowired
|
||||
private SuggestionService suggestionService;
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
log.info("Executing suggestion clean up job.");
|
||||
try {
|
||||
suggestionService.cleanUpSuggestions();
|
||||
} catch (Exception exception) {
|
||||
log.error("Suggestion clean up job failed.", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,15 @@ package dev.sheldan.abstracto.suggestion.repository;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.ServerSpecificId;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.Suggestion;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Repository
|
||||
public interface SuggestionRepository extends JpaRepository<Suggestion, ServerSpecificId> {
|
||||
List<Suggestion> findByUpdatedLessThanAndStateNot(Instant start, SuggestionState state);
|
||||
}
|
||||
|
||||
@@ -6,34 +6,33 @@ import dev.sheldan.abstracto.core.service.*;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
import dev.sheldan.abstracto.core.utils.FutureUtils;
|
||||
import dev.sheldan.abstracto.core.utils.MessageUtils;
|
||||
import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionPostTarget;
|
||||
import dev.sheldan.abstracto.suggestion.exception.SuggestionNotFoundException;
|
||||
import dev.sheldan.abstracto.suggestion.exception.SuggestionUpdateException;
|
||||
import dev.sheldan.abstracto.suggestion.exception.UnSuggestNotPossibleException;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.Suggestion;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
||||
import dev.sheldan.abstracto.suggestion.service.management.SuggestionManagementService;
|
||||
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.MessageEmbed;
|
||||
import net.dv8tion.jda.api.entities.TextChannel;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
public class SuggestionServiceBean implements SuggestionService {
|
||||
|
||||
public static final String SUGGESTION_LOG_TEMPLATE = "suggest_log";
|
||||
public static final String SUGGESTION_CREATION_TEMPLATE = "suggest_initial";
|
||||
public static final String SUGGESTION_UPDATE_TEMPLATE = "suggest_update";
|
||||
public static final String SUGGESTION_YES_EMOTE = "suggestionYes";
|
||||
public static final String SUGGESTION_NO_EMOTE = "suggestionNo";
|
||||
public static final String SUGGESTION_COUNTER_KEY = "suggestion";
|
||||
@@ -68,68 +67,105 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
@Autowired
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Autowired
|
||||
private MessageService messageService;
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@Value("${abstracto.feature.suggestion.removalMaxAge}")
|
||||
private Long removalMaxAgeSeconds;
|
||||
|
||||
@Value("${abstracto.feature.suggestion.removalDays}")
|
||||
private Long autoRemovalMaxDays;
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> createSuggestionMessage(Member member, String text, SuggestionLog suggestionLog) {
|
||||
AServer server = serverManagementService.loadServer(member.getGuild());
|
||||
AUserInAServer suggester = userInServerManagementService.loadOrCreateUser(member);
|
||||
public CompletableFuture<Void> createSuggestionMessage(Message commandMessage, String text) {
|
||||
Member suggester = commandMessage.getMember();
|
||||
Long serverId = suggester.getGuild().getIdLong();
|
||||
AServer server = serverManagementService.loadServer(serverId);
|
||||
AUserInAServer userSuggester = userInServerManagementService.loadOrCreateUser(suggester);
|
||||
Long newSuggestionId = counterService.getNextCounterValue(server, SUGGESTION_COUNTER_KEY);
|
||||
suggestionLog.setSuggestionId(newSuggestionId);
|
||||
suggestionLog.setState(SuggestionState.NEW);
|
||||
suggestionLog.setSuggesterUser(suggester);
|
||||
suggestionLog.setText(text);
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_LOG_TEMPLATE, suggestionLog, member.getGuild().getIdLong());
|
||||
long guildId = member.getGuild().getIdLong();
|
||||
log.info("Creating suggestion with id {} in server {} from member {}.", newSuggestionId, member.getGuild().getId(), member.getId());
|
||||
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, guildId);
|
||||
SuggestionLog model = SuggestionLog
|
||||
.builder()
|
||||
.suggestionId(newSuggestionId)
|
||||
.state(SuggestionState.NEW)
|
||||
.serverId(serverId)
|
||||
.message(commandMessage)
|
||||
.member(commandMessage.getMember())
|
||||
.suggesterUser(userSuggester)
|
||||
.suggester(suggester.getUser())
|
||||
.text(text)
|
||||
.build();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_CREATION_TEMPLATE, model, serverId);
|
||||
log.info("Creating suggestion with id {} in server {} from member {}.", newSuggestionId, serverId, suggester.getIdLong());
|
||||
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, serverId);
|
||||
return FutureUtils.toSingleFutureGeneric(completableFutures).thenCompose(aVoid -> {
|
||||
Message message = completableFutures.get(0).join();
|
||||
log.debug("Posted message, adding reaction for suggestion {} to message {}.", newSuggestionId, message.getId());
|
||||
CompletableFuture<Void> firstReaction = reactionService.addReactionToMessageAsync(SUGGESTION_YES_EMOTE, guildId, message);
|
||||
CompletableFuture<Void> secondReaction = reactionService.addReactionToMessageAsync(SUGGESTION_NO_EMOTE, guildId, message);
|
||||
CompletableFuture<Void> firstReaction = reactionService.addReactionToMessageAsync(SUGGESTION_YES_EMOTE, serverId, message);
|
||||
CompletableFuture<Void> secondReaction = reactionService.addReactionToMessageAsync(SUGGESTION_NO_EMOTE, serverId, message);
|
||||
return CompletableFuture.allOf(firstReaction, secondReaction).thenAccept(aVoid1 -> {
|
||||
log.debug("Reaction added to message {} for suggestion {}.", message.getId(), newSuggestionId);
|
||||
self.persistSuggestionInDatabase(member, text, message, newSuggestionId);
|
||||
self.persistSuggestionInDatabase(suggester, text, message, newSuggestionId, commandMessage);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void persistSuggestionInDatabase(Member member, String text, Message message, Long suggestionId) {
|
||||
public void persistSuggestionInDatabase(Member member, String text, Message message, Long suggestionId, Message commandMessage) {
|
||||
log.info("Persisting suggestion {} for server {} in database.", suggestionId, member.getGuild().getId());
|
||||
suggestionManagementService.createSuggestion(member, text, message, suggestionId);
|
||||
suggestionManagementService.createSuggestion(member, text, message, suggestionId, commandMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> acceptSuggestion(Long suggestionId, String text, SuggestionLog suggestionLog) {
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(suggestionId, suggestionLog.getGuild().getIdLong()).orElseThrow(() -> new SuggestionNotFoundException(suggestionId));
|
||||
public CompletableFuture<Void> acceptSuggestion(Long suggestionId, Message commandMessage, String text) {
|
||||
Long serverId = commandMessage.getGuild().getIdLong();
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
||||
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.ACCEPTED);
|
||||
log.info("Accepting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
|
||||
return updateSuggestion(text, suggestionLog, suggestion);
|
||||
return updateSuggestion(commandMessage.getMember(), text, suggestion);
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> updateSuggestion(String text, SuggestionLog suggestionLog, Suggestion suggestion) {
|
||||
suggestionLog.setSuggesterUser(suggestion.getSuggester());
|
||||
@Override
|
||||
public CompletableFuture<Void> vetoSuggestion(Long suggestionId, Message commandMessage, String text) {
|
||||
Long serverId = commandMessage.getGuild().getIdLong();
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
||||
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.VETOED);
|
||||
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) {
|
||||
Long serverId = suggestion.getServer().getId();
|
||||
Long channelId = suggestion.getChannel().getId();
|
||||
Long originalMessageId = suggestion.getMessageId();
|
||||
Long serverId = suggestion.getServer().getId();
|
||||
SuggestionLog model = SuggestionLog
|
||||
.builder()
|
||||
.suggestionId(suggestion.getSuggestionId().getId())
|
||||
.state(suggestion.getState())
|
||||
.suggesterUser(suggestion.getSuggester())
|
||||
.serverId(serverId)
|
||||
.member(memberExecutingCommand)
|
||||
.originalMessageId(originalMessageId)
|
||||
.text(suggestion.getSuggestionText())
|
||||
.originalChannelId(channelId)
|
||||
.reason(reason)
|
||||
.build();
|
||||
log.info("Updated posted suggestion {} in server {}.", suggestion.getSuggestionId().getId(), suggestion.getServer().getId());
|
||||
|
||||
suggestionLog.setOriginalChannelId(channelId);
|
||||
suggestionLog.setOriginalMessageId(originalMessageId);
|
||||
suggestionLog.setOriginalMessageUrl(MessageUtils.buildMessageUrl(serverId, channelId, originalMessageId));
|
||||
AUserInAServer suggester = suggestion.getSuggester();
|
||||
TextChannel textChannelById = channelService.getTextChannelFromServer(serverId, channelId);
|
||||
CompletableFuture<Member> memberById = memberService.getMemberInServerAsync(serverId, suggester.getUserReference().getId());
|
||||
suggestionLog.setState(suggestion.getState());
|
||||
suggestionLog.setSuggestionId(suggestion.getSuggestionId().getId());
|
||||
CompletableFuture<User> memberById = userService.retrieveUserForId(suggestion.getSuggester().getUserReference().getId());
|
||||
CompletableFuture<Void> finalFuture = new CompletableFuture<>();
|
||||
memberById.whenComplete((member, throwable) -> {
|
||||
memberById.whenComplete((user, throwable) -> {
|
||||
if(throwable == null) {
|
||||
suggestionLog.setSuggester(member);
|
||||
model.setSuggester(user);
|
||||
}
|
||||
channelService.retrieveMessageInChannel(textChannelById, originalMessageId).thenCompose(message ->
|
||||
self.updateSuggestionMessageText(text, suggestionLog, message)
|
||||
).thenAccept(aVoid -> finalFuture.complete(null));
|
||||
self.updateSuggestionMessageText(reason, model).thenAccept(unused -> finalFuture.complete(null)).exceptionally(throwable1 -> {
|
||||
finalFuture.completeExceptionally(throwable1);
|
||||
return null;
|
||||
});
|
||||
}).exceptionally(throwable -> {
|
||||
finalFuture.completeExceptionally(throwable);
|
||||
return null;
|
||||
});
|
||||
|
||||
return finalFuture;
|
||||
@@ -137,27 +173,48 @@ public class SuggestionServiceBean implements SuggestionService {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public CompletableFuture<Void> updateSuggestionMessageText(String text, SuggestionLog suggestionLog, Message message) {
|
||||
Optional<MessageEmbed> embedOptional = message.getEmbeds().stream().filter(embed -> embed.getDescription() != null).findFirst();
|
||||
if(embedOptional.isPresent()) {
|
||||
log.info("Updating the text of the suggestion {} in server {}.", suggestionLog.getSuggestionId(), message.getGuild().getId());
|
||||
MessageEmbed suggestionEmbed = embedOptional.get();
|
||||
suggestionLog.setReason(text);
|
||||
suggestionLog.setText(suggestionEmbed.getDescription());
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_LOG_TEMPLATE, suggestionLog, suggestionLog.getGuild().getIdLong());
|
||||
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, suggestionLog.getGuild().getIdLong());
|
||||
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]));
|
||||
} else {
|
||||
log.warn("The message to update the suggestion for, did not contain an embed to update. Suggestions require an embed with a description as a container. MessageURL: {}", message.getJumpUrl());
|
||||
throw new SuggestionUpdateException();
|
||||
}
|
||||
public CompletableFuture<Void> updateSuggestionMessageText(String text, SuggestionLog suggestionLog) {
|
||||
suggestionLog.setReason(text);
|
||||
Long serverId = suggestionLog.getServerId();
|
||||
MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_UPDATE_TEMPLATE, suggestionLog, serverId);
|
||||
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, serverId);
|
||||
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> rejectSuggestion(Long suggestionId, String text, SuggestionLog suggestionLog) {
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(suggestionId, suggestionLog.getGuild().getIdLong()).orElseThrow(() -> new SuggestionNotFoundException(suggestionId));
|
||||
public CompletableFuture<Void> rejectSuggestion(Long suggestionId, Message commandMessage, String text) {
|
||||
Long serverId = commandMessage.getGuild().getIdLong();
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
||||
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.REJECTED);
|
||||
log.info("Rejecting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
|
||||
return updateSuggestion(text, suggestionLog, suggestion);
|
||||
return updateSuggestion(commandMessage.getMember(), text, suggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> removeSuggestion(Long suggestionId, Member member) {
|
||||
Long serverId = member.getGuild().getIdLong();
|
||||
Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId);
|
||||
if(member.getIdLong() != suggestion.getSuggester().getUserReference().getId() ||
|
||||
suggestion.getCreated().isBefore(Instant.now().minus(Duration.ofSeconds(removalMaxAgeSeconds)))) {
|
||||
throw new UnSuggestNotPossibleException();
|
||||
}
|
||||
return messageService.deleteMessageInChannelInServer(suggestion.getServer().getId(), suggestion.getChannel().getId(), suggestion.getMessageId())
|
||||
.thenAccept(unused -> self.deleteSuggestion(suggestionId, serverId));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void cleanUpSuggestions() {
|
||||
Instant pointInTime = Instant.now().minus(Duration.ofDays(autoRemovalMaxDays)).truncatedTo(ChronoUnit.DAYS);
|
||||
List<Suggestion> suggestionsToRemove = suggestionManagementService.getSuggestionsUpdatedBeforeNotNew(pointInTime);
|
||||
log.info("Removing {} suggestions older than {}.", suggestionsToRemove.size(), pointInTime);
|
||||
suggestionsToRemove.forEach(suggestion -> log.info("Deleting suggestion {} in server {}.",
|
||||
suggestion.getSuggestionId().getId(), suggestion.getSuggestionId().getServerId()));
|
||||
suggestionManagementService.deleteSuggestion(suggestionsToRemove);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void deleteSuggestion(Long suggestionId, Long serverId) {
|
||||
suggestionManagementService.deleteSuggestion(serverId, suggestionId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.ServerManagementService;
|
||||
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
|
||||
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.repository.SuggestionRepository;
|
||||
@@ -16,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@@ -35,35 +37,42 @@ public class SuggestionManagementServiceBean implements SuggestionManagementServ
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Override
|
||||
public Suggestion createSuggestion(Member suggester, String text, Message message, Long suggestionId) {
|
||||
public Suggestion createSuggestion(Member suggester, String text, Message message, Long suggestionId, Message commandMessage) {
|
||||
AUserInAServer user = userInServerManagementService.loadOrCreateUser(suggester);
|
||||
return this.createSuggestion(user, text, message, suggestionId);
|
||||
return this.createSuggestion(user, text, message, suggestionId, commandMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Suggestion createSuggestion(AUserInAServer suggester, String text, Message message, Long suggestionId) {
|
||||
long channelId = message.getChannel().getIdLong();
|
||||
public Suggestion createSuggestion(AUserInAServer suggester, String text, Message createdMessage, Long suggestionId, Message commandMessage) {
|
||||
long channelId = createdMessage.getChannel().getIdLong();
|
||||
AChannel channel = channelManagementService.loadChannel(channelId);
|
||||
AChannel commandChannel = channelManagementService.loadChannel(commandMessage.getChannel().getIdLong());
|
||||
Suggestion suggestion = Suggestion
|
||||
.builder()
|
||||
.state(SuggestionState.NEW)
|
||||
.suggester(suggester)
|
||||
.suggestionText(text)
|
||||
.suggestionId(new ServerSpecificId(suggester.getServerReference().getId(), suggestionId))
|
||||
.server(suggester.getServerReference())
|
||||
.suggestionDate(Instant.now())
|
||||
.channel(channel)
|
||||
.messageId(message.getIdLong())
|
||||
.commandChannel(commandChannel)
|
||||
.commandMessageId(commandMessage.getIdLong())
|
||||
.messageId(createdMessage.getIdLong())
|
||||
.build();
|
||||
log.info("Persisting suggestion {} at message {} in channel {} on server {} from user {}.",
|
||||
suggestionId, message.getId(), channelId, message.getGuild().getId(), suggester.getUserReference().getId());
|
||||
suggestionId, createdMessage.getId(), channelId, createdMessage.getGuild().getId(), suggester.getUserReference().getId());
|
||||
return suggestionRepository.save(suggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Suggestion> getSuggestion(Long suggestionId, Long serverId) {
|
||||
public Optional<Suggestion> getSuggestionOptional(Long serverId, Long suggestionId) {
|
||||
return suggestionRepository.findById(new ServerSpecificId(serverId, suggestionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Suggestion getSuggestion(Long serverId, Long suggestionId) {
|
||||
return getSuggestionOptional(serverId, suggestionId).orElseThrow(() -> new SuggestionNotFoundException(suggestionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSuggestionState(Suggestion suggestion, SuggestionState newState) {
|
||||
@@ -71,4 +80,25 @@ public class SuggestionManagementServiceBean implements SuggestionManagementServ
|
||||
log.info("Setting suggestion {} in server {} to state {}.", suggestion.getSuggestionId().getId(), suggestion.getSuggestionId().getServerId(), newState);
|
||||
suggestionRepository.save(suggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSuggestion(Long serverId, Long suggestionId) {
|
||||
deleteSuggestion(getSuggestion(serverId, suggestionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSuggestion(List<Suggestion> suggestions) {
|
||||
suggestionRepository.deleteAll(suggestions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteSuggestion(Suggestion suggestion) {
|
||||
log.info("Deleting suggestion {} in server {}.", suggestion.getSuggestionId().getId(), suggestion.getSuggestionId().getServerId());
|
||||
suggestionRepository.delete(suggestion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Suggestion> getSuggestionsUpdatedBeforeNotNew(Instant date) {
|
||||
return suggestionRepository.findByUpdatedLessThanAndStateNot(date, SuggestionState.NEW);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,16 @@
|
||||
<column name="module_id" valueComputed="${utilityModule}"/>
|
||||
<column name="feature_id" valueComputed="${suggestionFeature}"/>
|
||||
</insert>
|
||||
<insert tableName="command">
|
||||
<column name="name" value="unSuggest"/>
|
||||
<column name="module_id" valueComputed="${utilityModule}"/>
|
||||
<column name="feature_id" valueComputed="${suggestionFeature}"/>
|
||||
</insert>
|
||||
<insert tableName="command">
|
||||
<column name="name" value="veto"/>
|
||||
<column name="module_id" valueComputed="${utilityModule}"/>
|
||||
<column name="feature_id" valueComputed="${suggestionFeature}"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@@ -9,4 +9,5 @@
|
||||
<include file="default_emote.xml" relativeToChangelogFile="true"/>
|
||||
<include file="feature.xml" relativeToChangelogFile="true"/>
|
||||
<include file="command.xml" relativeToChangelogFile="true"/>
|
||||
<include file="suggestion_cleanup_job.xml" relativeToChangelogFile="true"/>
|
||||
</databaseChangeLog>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog ../../dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext ../../dbchangelog-3.8.xsd
|
||||
http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" >
|
||||
<changeSet author="Sheldan" id="suggestion-cleanup-insert">
|
||||
<insert tableName="scheduler_job">
|
||||
<column name="name" value="suggestionCleanUpJob"/>
|
||||
<column name="group_name" value="suggestion"/>
|
||||
<column name="clazz" value="dev.sheldan.abstracto.suggestion.job.SuggestionCleanUpJob"/>
|
||||
<column name="active" value="true"/>
|
||||
<column name="cron_expression" value="0 0 0 * * ?"/>
|
||||
<column name="recovery" value="false"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -17,9 +17,6 @@
|
||||
<column name="state" type="VARCHAR(255)">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="suggestion_date" type="TIMESTAMP WITHOUT TIME ZONE">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
<column name="created" type="TIMESTAMP WITHOUT TIME ZONE">
|
||||
<constraints nullable="true"/>
|
||||
</column>
|
||||
@@ -33,11 +30,29 @@
|
||||
<column name="suggester_user_in_server_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="suggestion_text" type="VARCHAR(2000)">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="command_message_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="command_channel_id" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<addPrimaryKey columnNames="server_id, id" tableName="suggestion" constraintName="pk_suggestion" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="channel_id" baseTableName="suggestion" constraintName="fk_suggestion_channel" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="channel" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="suggester_user_in_server_id" baseTableName="suggestion" constraintName="fk_suggestion_suggester" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="suggestion" constraintName="fk_suggestion_server" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="id" referencedTableName="server" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="channel_id" baseTableName="suggestion" constraintName="fk_suggestion_channel"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="id" referencedTableName="channel" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="command_channel_id" baseTableName="suggestion" constraintName="fk_suggestion_command_channel"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="id" referencedTableName="channel" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="suggester_user_in_server_id" baseTableName="suggestion" constraintName="fk_suggestion_suggester"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="user_in_server_id" referencedTableName="user_in_server" validate="true"/>
|
||||
<addForeignKeyConstraint baseColumnNames="server_id" baseTableName="suggestion" constraintName="fk_suggestion_server"
|
||||
deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="id" referencedTableName="server" validate="true"/>
|
||||
<sql>
|
||||
DROP TRIGGER IF EXISTS suggestion_update_trigger ON suggestion;
|
||||
CREATE TRIGGER suggestion_update_trigger BEFORE UPDATE ON suggestion FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure();
|
||||
@@ -47,7 +62,7 @@
|
||||
CREATE TRIGGER suggestion_insert_trigger BEFORE INSERT ON suggestion FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure();
|
||||
</sql>
|
||||
<sql>
|
||||
ALTER TABLE suggestion ADD CONSTRAINT check_suggestion_state CHECK (state IN ('NEW','ACCEPTED', 'REJECTED'));
|
||||
ALTER TABLE suggestion ADD CONSTRAINT check_suggestion_state CHECK (state IN ('NEW','ACCEPTED', 'REJECTED', 'VETOED'));
|
||||
</sql>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -3,3 +3,5 @@ abstracto.featureFlags.suggestion.enabled=false
|
||||
|
||||
abstracto.postTargets.suggestions.name=suggestions
|
||||
|
||||
abstracto.feature.suggestion.removalMaxAge=3600
|
||||
abstracto.feature.suggestion.removalDays=2
|
||||
@@ -34,9 +34,9 @@ public class AcceptTest {
|
||||
String text = "text";
|
||||
Long suggestionId = 5L;
|
||||
CommandContext context = CommandTestUtilities.getWithParameters(Arrays.asList(suggestionId, text));
|
||||
when(suggestionService.acceptSuggestion(eq(suggestionId), eq(text), any(SuggestionLog.class))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(suggestionService.acceptSuggestion(eq(suggestionId), eq(context.getMessage()), eq(text))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);
|
||||
verify(suggestionService, times(1)).acceptSuggestion(eq(suggestionId), eq(text), any(SuggestionLog.class));
|
||||
verify(suggestionService, times(1)).acceptSuggestion(eq(suggestionId), eq(context.getMessage()), eq(text));
|
||||
CommandTestUtilities.checkSuccessfulCompletion(result.get());
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@ public class RejectTest {
|
||||
String text = "text";
|
||||
Long suggestionId = 5L;
|
||||
CommandContext context = CommandTestUtilities.getWithParameters(Arrays.asList(suggestionId, text));
|
||||
when(suggestionService.rejectSuggestion(eq(suggestionId), eq(text), any(SuggestionLog.class))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(suggestionService.rejectSuggestion(eq(suggestionId), eq(context.getMessage()), eq(text))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);
|
||||
verify(suggestionService, times(1)).rejectSuggestion(eq(suggestionId), eq(text), any(SuggestionLog.class));
|
||||
verify(suggestionService, times(1)).rejectSuggestion(eq(suggestionId), eq(context.getMessage()), eq(text));
|
||||
CommandTestUtilities.checkSuccessfulCompletion(result.get());
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ public class SuggestTest {
|
||||
public void testExecuteCommand() throws ExecutionException, InterruptedException {
|
||||
String text = "text";
|
||||
CommandContext context = CommandTestUtilities.getWithParameters(Arrays.asList(text));
|
||||
when(suggestionService.createSuggestionMessage(eq(context.getAuthor()), eq(text), any(SuggestionLog.class))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
when(suggestionService.createSuggestionMessage(eq(context.getMessage()), eq(text))).thenReturn(CompletableFuture.completedFuture(null));
|
||||
CompletableFuture<CommandResult> result = testUnit.executeAsync(context);
|
||||
verify(suggestionService, times(1)).createSuggestionMessage(eq(context.getAuthor()), eq(text), any(SuggestionLog.class));
|
||||
verify(suggestionService, times(1)).createSuggestionMessage(eq(context.getMessage()), eq(text));
|
||||
CommandTestUtilities.checkSuccessfulCompletion(result.get());
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import dev.sheldan.abstracto.core.templating.model.MessageToSend;
|
||||
import dev.sheldan.abstracto.core.templating.service.TemplateService;
|
||||
import dev.sheldan.abstracto.suggestion.config.SuggestionPostTarget;
|
||||
import dev.sheldan.abstracto.suggestion.exception.SuggestionNotFoundException;
|
||||
import dev.sheldan.abstracto.suggestion.exception.SuggestionUpdateException;
|
||||
import dev.sheldan.abstracto.suggestion.exception.UnSuggestNotPossibleException;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.Suggestion;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
||||
@@ -28,7 +28,6 @@ import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
@@ -62,9 +61,6 @@ public class SuggestionServiceBeanTest {
|
||||
@Mock
|
||||
private SuggestionServiceBean self;
|
||||
|
||||
@Mock
|
||||
private Member suggestionCreator;
|
||||
|
||||
@Mock
|
||||
private Guild guild;
|
||||
|
||||
@@ -80,6 +76,9 @@ public class SuggestionServiceBeanTest {
|
||||
@Mock
|
||||
private ServerManagementService serverManagementService;
|
||||
|
||||
@Mock
|
||||
private UserService userService;
|
||||
|
||||
@Mock
|
||||
private AServer server;
|
||||
|
||||
@@ -90,164 +89,103 @@ public class SuggestionServiceBeanTest {
|
||||
private AUserInAServer suggester;
|
||||
|
||||
@Mock
|
||||
private AUser suggesterUser;
|
||||
private User suggesterUser;
|
||||
|
||||
@Mock
|
||||
private Member suggesterMember;
|
||||
private Member member;
|
||||
|
||||
@Mock
|
||||
private Message message;
|
||||
|
||||
private static final Long SUGGESTER_ID = 8L;
|
||||
private static final Long SERVER_ID = 3L;
|
||||
private static final Long CHANNEL_ID = 7L;
|
||||
private static final Long SUGGESTION_ID = 5L;
|
||||
private static final Long USER_ID = 6L;
|
||||
|
||||
@Test
|
||||
public void testCreateSuggestionMessage() {
|
||||
String suggestionText = "text";
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
when(suggestionCreator.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
when(serverManagementService.loadServer(suggestionCreator.getGuild())).thenReturn(server);
|
||||
when(serverManagementService.loadServer(SERVER_ID)).thenReturn(server);
|
||||
MessageToSend messageToSend = Mockito.mock(MessageToSend.class);
|
||||
when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_LOG_TEMPLATE), any(SuggestionLog.class), eq(SERVER_ID))).thenReturn(messageToSend);
|
||||
when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_CREATION_TEMPLATE), any(SuggestionLog.class), eq(SERVER_ID))).thenReturn(messageToSend);
|
||||
Message suggestionMessage = Mockito.mock(Message.class);
|
||||
when(counterService.getNextCounterValue(server, SuggestionServiceBean.SUGGESTION_COUNTER_KEY)).thenReturn(SUGGESTION_ID);
|
||||
AUserInAServer aUserInAServer = Mockito.mock(AUserInAServer.class);
|
||||
when(userInServerManagementService.loadOrCreateUser(suggestionCreator)).thenReturn(aUserInAServer);
|
||||
List<CompletableFuture<Message>> postingFutures = Arrays.asList(CompletableFuture.completedFuture(suggestionMessage));
|
||||
when(postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, SERVER_ID)).thenReturn(postingFutures);
|
||||
testUnit.createSuggestionMessage(suggestionCreator, suggestionText, log);
|
||||
when(message.getMember()).thenReturn(member);
|
||||
when(member.getGuild()).thenReturn(guild);
|
||||
when(member.getIdLong()).thenReturn(SUGGESTER_ID);
|
||||
testUnit.createSuggestionMessage(message, suggestionText);
|
||||
verify(reactionService, times(1)).addReactionToMessageAsync(SuggestionServiceBean.SUGGESTION_YES_EMOTE, SERVER_ID, suggestionMessage);
|
||||
verify(reactionService, times(1)).addReactionToMessageAsync(SuggestionServiceBean.SUGGESTION_NO_EMOTE, SERVER_ID, suggestionMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSuggestion() {
|
||||
when(suggesterMember.getGuild()).thenReturn(guild);
|
||||
when(member.getGuild()).thenReturn(guild);
|
||||
when(guild.getId()).thenReturn("5");
|
||||
String text = "text";
|
||||
Message message = Mockito.mock(Message.class);
|
||||
testUnit.persistSuggestionInDatabase(suggesterMember, text, message, SUGGESTION_ID);
|
||||
verify(suggestionManagementService, times(1)).createSuggestion(suggesterMember, text, message, SUGGESTION_ID);
|
||||
Message commandMessage = Mockito.mock(Message.class);
|
||||
testUnit.persistSuggestionInDatabase(member, text, message, SUGGESTION_ID, commandMessage);
|
||||
verify(suggestionManagementService, times(1)).createSuggestion(member, text, message, SUGGESTION_ID, commandMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptExistingSuggestion() {
|
||||
executeAcceptWithMember(suggesterMember);
|
||||
executeAcceptWithMember();
|
||||
}
|
||||
|
||||
@Test(expected = SuggestionNotFoundException.class)
|
||||
public void testAcceptNotExistingSuggestion() {
|
||||
when(suggestionManagementService.getSuggestion(SUGGESTION_ID, SERVER_ID)).thenReturn(Optional.empty());
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
when(log.getGuild()).thenReturn(guild);
|
||||
when(suggestionManagementService.getSuggestion(SERVER_ID, SUGGESTION_ID)).thenThrow(new SuggestionNotFoundException(SUGGESTION_ID));
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
testUnit.acceptSuggestion(SUGGESTION_ID, CLOSING_TEXT, log);
|
||||
when(message.getGuild()).thenReturn(guild);
|
||||
testUnit.acceptSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptSuggestionWithMemberLeavingGuild() {
|
||||
executeAcceptWithMember(null);
|
||||
}
|
||||
|
||||
@Test(expected = ChannelNotInGuildException.class)
|
||||
public void testAcceptSuggestionInNoTextChannel() {
|
||||
setupForNoTextChannel();
|
||||
public void testUpdateSuggestionMessage() {
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
when(log.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
testUnit.acceptSuggestion(SUGGESTION_ID, CLOSING_TEXT, log);
|
||||
}
|
||||
|
||||
private void setupForNoTextChannel() {
|
||||
Long messageId = 7L;
|
||||
Suggestion suggestionToAccept = Mockito.mock(Suggestion.class);
|
||||
when(suggestionToAccept.getChannel()).thenReturn(channel);
|
||||
when(suggestionToAccept.getServer()).thenReturn(server);
|
||||
when(suggestionToAccept.getSuggester()).thenReturn(suggester);
|
||||
ServerSpecificId suggestionId = Mockito.mock(ServerSpecificId.class);
|
||||
when(suggestionId.getId()).thenReturn(SUGGESTION_ID);
|
||||
when(suggestionToAccept.getSuggestionId()).thenReturn(suggestionId);
|
||||
when(suggestionToAccept.getMessageId()).thenReturn(messageId);
|
||||
when(server.getId()).thenReturn(SERVER_ID);
|
||||
when(channel.getId()).thenReturn(CHANNEL_ID);
|
||||
when(channelService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenThrow(new ChannelNotInGuildException(CHANNEL_ID));
|
||||
when(suggestionManagementService.getSuggestion(SUGGESTION_ID, SERVER_ID)).thenReturn(Optional.of(suggestionToAccept));
|
||||
}
|
||||
|
||||
@Test(expected = SuggestionUpdateException.class)
|
||||
public void testUpdateSuggestionTextWithoutEmbed() {
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
Message suggestionMessage = Mockito.mock(Message.class);
|
||||
testUnit.updateSuggestionMessageText(CLOSING_TEXT, log, suggestionMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateSuggestionMessageWithEmbed() {
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
when(log.getGuild()).thenReturn(guild);
|
||||
MessageEmbed embed = Mockito.mock(MessageEmbed.class);
|
||||
when(embed.getDescription()).thenReturn("description");
|
||||
Message suggestionMessage = Mockito.mock(Message.class);
|
||||
when(suggestionMessage.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
when(suggestionMessage.getEmbeds()).thenReturn(Arrays.asList(embed));
|
||||
when(log.getServerId()).thenReturn(SERVER_ID);
|
||||
MessageToSend updatedMessage = Mockito.mock(MessageToSend.class);
|
||||
when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_LOG_TEMPLATE), any(SuggestionLog.class), eq(SERVER_ID))).thenReturn(updatedMessage);
|
||||
testUnit.updateSuggestionMessageText(CLOSING_TEXT, log, suggestionMessage);
|
||||
when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_UPDATE_TEMPLATE), any(SuggestionLog.class), eq(SERVER_ID))).thenReturn(updatedMessage);
|
||||
testUnit.updateSuggestionMessageText(CLOSING_TEXT, log);
|
||||
verify(postTargetService, times(1)).sendEmbedInPostTarget(updatedMessage, SuggestionPostTarget.SUGGESTION, SERVER_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRejectExistingSuggestion() {
|
||||
executeRejectWithMember(suggesterMember);
|
||||
executeRejectWithMember();
|
||||
}
|
||||
|
||||
@Test(expected = SuggestionNotFoundException.class)
|
||||
public void testRejectNotExistingSuggestion() {
|
||||
when(suggestionManagementService.getSuggestion(SUGGESTION_ID, SERVER_ID)).thenReturn(Optional.empty());
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
when(log.getGuild()).thenReturn(guild);
|
||||
when(suggestionManagementService.getSuggestion(SERVER_ID, SUGGESTION_ID)).thenThrow(new SuggestionNotFoundException(SUGGESTION_ID));
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
testUnit.rejectSuggestion(SUGGESTION_ID, CLOSING_TEXT, log);
|
||||
when(message.getGuild()).thenReturn(guild);
|
||||
testUnit.rejectSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRejectSuggestionWithMemberLeavingGuild() {
|
||||
executeRejectWithMember(null);
|
||||
}
|
||||
|
||||
@Test(expected = ChannelNotInGuildException.class)
|
||||
public void testRejectSuggestionInNoTextChannel() {
|
||||
setupForNoTextChannel();
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
when(log.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
testUnit.rejectSuggestion(SUGGESTION_ID, CLOSING_TEXT, log);
|
||||
}
|
||||
|
||||
private void executeAcceptWithMember(Member actualMember) {
|
||||
private void executeAcceptWithMember() {
|
||||
Long messageId = 7L;
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
when(log.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
Suggestion suggestionToAccept = setupClosing(messageId);
|
||||
Message suggestionMessage = Mockito.mock(Message.class);
|
||||
when(channelService.retrieveMessageInChannel(textChannel, messageId)).thenReturn(CompletableFuture.completedFuture(suggestionMessage));
|
||||
when(memberService.getMemberInServerAsync(SERVER_ID, SUGGESTER_ID)).thenReturn(CompletableFuture.completedFuture(actualMember));
|
||||
testUnit.acceptSuggestion(SUGGESTION_ID, CLOSING_TEXT, log);
|
||||
when(message.getGuild()).thenReturn(guild);
|
||||
when(message.getMember()).thenReturn(member);
|
||||
testUnit.acceptSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||
verify(suggestionManagementService, times(1)).setSuggestionState(suggestionToAccept, SuggestionState.ACCEPTED);
|
||||
}
|
||||
|
||||
private void executeRejectWithMember(Member actualMember) {
|
||||
private void executeRejectWithMember() {
|
||||
Long messageId = 7L;
|
||||
SuggestionLog log = Mockito.mock(SuggestionLog.class);
|
||||
when(log.getGuild()).thenReturn(guild);
|
||||
when(guild.getIdLong()).thenReturn(SERVER_ID);
|
||||
Suggestion suggestionToAccept = setupClosing(messageId);
|
||||
Message suggestionMessage = Mockito.mock(Message.class);
|
||||
when(channelService.retrieveMessageInChannel(textChannel, messageId)).thenReturn(CompletableFuture.completedFuture(suggestionMessage));
|
||||
when(memberService.getMemberInServerAsync(SERVER_ID, SUGGESTER_ID)).thenReturn(CompletableFuture.completedFuture(actualMember));
|
||||
testUnit.rejectSuggestion(SUGGESTION_ID, CLOSING_TEXT, log);
|
||||
when(message.getGuild()).thenReturn(guild);
|
||||
when(message.getMember()).thenReturn(member);
|
||||
testUnit.rejectSuggestion(SUGGESTION_ID, message, CLOSING_TEXT);
|
||||
verify(suggestionManagementService, times(1)).setSuggestionState(suggestionToAccept, SuggestionState.REJECTED);
|
||||
}
|
||||
|
||||
@@ -256,16 +194,17 @@ public class SuggestionServiceBeanTest {
|
||||
when(suggestionToAccept.getChannel()).thenReturn(channel);
|
||||
when(suggestionToAccept.getServer()).thenReturn(server);
|
||||
when(suggestionToAccept.getSuggester()).thenReturn(suggester);
|
||||
AUser aUser = Mockito.mock(AUser.class);
|
||||
when(aUser.getId()).thenReturn(USER_ID);
|
||||
when(suggester.getUserReference()).thenReturn(aUser);
|
||||
ServerSpecificId suggestionId = Mockito.mock(ServerSpecificId.class);
|
||||
when(suggestionId.getId()).thenReturn(SUGGESTION_ID);
|
||||
when(suggestionToAccept.getSuggestionId()).thenReturn(suggestionId);
|
||||
when(suggestionToAccept.getMessageId()).thenReturn(messageId);
|
||||
when(server.getId()).thenReturn(SERVER_ID);
|
||||
when(channel.getId()).thenReturn(CHANNEL_ID);
|
||||
when(suggester.getUserReference()).thenReturn(suggesterUser);
|
||||
when(suggesterUser.getId()).thenReturn(SUGGESTER_ID);
|
||||
when(suggestionManagementService.getSuggestion(SUGGESTION_ID, SERVER_ID)).thenReturn(Optional.of(suggestionToAccept));
|
||||
when(channelService.getTextChannelFromServer(SERVER_ID, CHANNEL_ID)).thenReturn(textChannel);
|
||||
when(userService.retrieveUserForId(USER_ID)).thenReturn(CompletableFuture.completedFuture(suggesterUser));
|
||||
when(suggestionManagementService.getSuggestion(SERVER_ID, SUGGESTION_ID)).thenReturn(suggestionToAccept);
|
||||
return suggestionToAccept;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,9 @@ public class SuggestionManagementServiceBeanTest {
|
||||
ArgumentCaptor<Suggestion> suggestionArgumentCaptor = ArgumentCaptor.forClass(Suggestion.class);
|
||||
Suggestion savedSuggestion = Mockito.mock(Suggestion.class);
|
||||
when(suggestionRepository.save(suggestionArgumentCaptor.capture())).thenReturn(savedSuggestion);
|
||||
Suggestion createdSuggestion = testUnit.createSuggestion(aUserInAServer, text, message, suggestionId);
|
||||
Message commandMessage = Mockito.mock(Message.class);
|
||||
when(commandMessage.getChannel()).thenReturn(messageChannel);
|
||||
Suggestion createdSuggestion = testUnit.createSuggestion(aUserInAServer, text, message, suggestionId, commandMessage);
|
||||
Assert.assertEquals(savedSuggestion, createdSuggestion);
|
||||
Suggestion capturedSuggestion = suggestionArgumentCaptor.getValue();
|
||||
Assert.assertEquals(SuggestionState.NEW, capturedSuggestion.getState());
|
||||
@@ -100,7 +102,9 @@ public class SuggestionManagementServiceBeanTest {
|
||||
ArgumentCaptor<Suggestion> suggestionArgumentCaptor = ArgumentCaptor.forClass(Suggestion.class);
|
||||
Suggestion savedSuggestion = Mockito.mock(Suggestion.class);
|
||||
when(suggestionRepository.save(suggestionArgumentCaptor.capture())).thenReturn(savedSuggestion);
|
||||
Suggestion createdSuggestion = testUnit.createSuggestion(member, text, message, suggestionId);
|
||||
Message commandMessage = Mockito.mock(Message.class);
|
||||
when(commandMessage.getChannel()).thenReturn(messageChannel);
|
||||
Suggestion createdSuggestion = testUnit.createSuggestion(member, text, message, suggestionId, commandMessage);
|
||||
Assert.assertEquals(savedSuggestion, createdSuggestion);
|
||||
Suggestion capturedSuggestion = suggestionArgumentCaptor.getValue();
|
||||
Assert.assertEquals(SuggestionState.NEW, capturedSuggestion.getState());
|
||||
@@ -112,7 +116,7 @@ public class SuggestionManagementServiceBeanTest {
|
||||
public void testGetSuggestion() {
|
||||
Suggestion foundSuggestion = createSuggestion();
|
||||
when(suggestionRepository.findById(new ServerSpecificId(SERVER_ID, SUGGESTION_ID))).thenReturn(Optional.of(foundSuggestion));
|
||||
Optional<Suggestion> suggestionOptional = testUnit.getSuggestion(SUGGESTION_ID, SERVER_ID);
|
||||
Optional<Suggestion> suggestionOptional = testUnit.getSuggestionOptional(SERVER_ID, SUGGESTION_ID);
|
||||
Assert.assertTrue(suggestionOptional.isPresent());
|
||||
suggestionOptional.ifPresent(suggestion -> Assert.assertEquals(SUGGESTION_ID, suggestion.getSuggestionId().getId().longValue()));
|
||||
}
|
||||
@@ -120,7 +124,7 @@ public class SuggestionManagementServiceBeanTest {
|
||||
@Test
|
||||
public void testGetSuggestionNotFound() {
|
||||
when(suggestionRepository.findById(new ServerSpecificId(SERVER_ID, SUGGESTION_ID))).thenReturn(Optional.empty());
|
||||
Optional<Suggestion> suggestionOptional = testUnit.getSuggestion(SUGGESTION_ID, SERVER_ID);
|
||||
Optional<Suggestion> suggestionOptional = testUnit.getSuggestionOptional(SERVER_ID, SUGGESTION_ID);
|
||||
Assert.assertFalse(suggestionOptional.isPresent());
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@ package dev.sheldan.abstracto.suggestion.exception;
|
||||
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
|
||||
import dev.sheldan.abstracto.core.templating.Templatable;
|
||||
|
||||
public class SuggestionUpdateException extends AbstractoRunTimeException implements Templatable {
|
||||
public SuggestionUpdateException() {
|
||||
super("Not possible to update suggestion.");
|
||||
public class UnSuggestNotPossibleException extends AbstractoRunTimeException implements Templatable {
|
||||
public UnSuggestNotPossibleException() {
|
||||
super("Not possible to remove suggestion.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTemplateName() {
|
||||
return "suggestion_update_exception";
|
||||
return "un_suggest_not_possible_exception";
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,10 +44,6 @@ public class Suggestion implements Serializable {
|
||||
@JoinColumn(name = "server_id", referencedColumnName = "id", nullable = false)
|
||||
private AServer server;
|
||||
|
||||
@Getter
|
||||
@Column(name = "suggestion_date")
|
||||
private Instant suggestionDate;
|
||||
|
||||
@Getter
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "state")
|
||||
@@ -59,4 +55,15 @@ public class Suggestion implements Serializable {
|
||||
@Column(name = "updated")
|
||||
private Instant updated;
|
||||
|
||||
@Column(name = "suggestion_text")
|
||||
private String suggestionText;
|
||||
|
||||
@Getter
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "command_channel_id")
|
||||
private AChannel commandChannel;
|
||||
|
||||
@Column(name = "command_message_id")
|
||||
private Long commandMessageId;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package dev.sheldan.abstracto.suggestion.model.database;
|
||||
|
||||
public enum SuggestionState {
|
||||
NEW, ACCEPTED, REJECTED
|
||||
NEW, ACCEPTED, REJECTED, VETOED
|
||||
}
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
package dev.sheldan.abstracto.suggestion.model.template;
|
||||
|
||||
import dev.sheldan.abstracto.core.models.context.UserInitiatedServerContext;
|
||||
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
|
||||
import dev.sheldan.abstracto.core.utils.MessageUtils;
|
||||
import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.User;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@SuperBuilder
|
||||
// TODO change user initiated context so slim context, and remove database entities referenced
|
||||
public class SuggestionLog extends UserInitiatedServerContext {
|
||||
public class SuggestionLog {
|
||||
private Long suggestionId;
|
||||
private SuggestionState state;
|
||||
private Member suggester;
|
||||
private User suggester;
|
||||
private Member member;
|
||||
private AUserInAServer suggesterUser;
|
||||
private String text;
|
||||
private Message message;
|
||||
private String reason;
|
||||
private Long originalMessageId;
|
||||
private Long serverId;
|
||||
private Long originalChannelId;
|
||||
private String originalMessageUrl;
|
||||
private Long originalMessageId;
|
||||
|
||||
public String getOriginalMessageUrl() {
|
||||
return MessageUtils.buildMessageUrl(serverId, originalChannelId , originalMessageId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package dev.sheldan.abstracto.suggestion.service;
|
||||
|
||||
import dev.sheldan.abstracto.suggestion.model.template.SuggestionLog;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface SuggestionService {
|
||||
CompletableFuture<Void> createSuggestionMessage(Member member, String text, SuggestionLog log);
|
||||
CompletableFuture<Void> acceptSuggestion(Long suggestionId, String text, SuggestionLog log);
|
||||
CompletableFuture<Void> rejectSuggestion(Long suggestionId, String text, SuggestionLog log);
|
||||
CompletableFuture<Void> createSuggestionMessage(Message commandMessage, String text);
|
||||
CompletableFuture<Void> acceptSuggestion(Long suggestionId, Message commandMessage, String text);
|
||||
CompletableFuture<Void> vetoSuggestion(Long suggestionId, Message commandMessage, String text);
|
||||
CompletableFuture<Void> rejectSuggestion(Long suggestionId, Message commandMessage, String text);
|
||||
CompletableFuture<Void> removeSuggestion(Long suggestionId, Member member);
|
||||
void cleanUpSuggestions();
|
||||
}
|
||||
|
||||
@@ -6,11 +6,18 @@ import dev.sheldan.abstracto.suggestion.model.database.SuggestionState;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface SuggestionManagementService {
|
||||
Suggestion createSuggestion(Member suggester, String text, Message message, Long suggestionId);
|
||||
Suggestion createSuggestion(AUserInAServer suggester, String text, Message message, Long suggestionId);
|
||||
Optional<Suggestion> getSuggestion(Long suggestionId, Long serverId);
|
||||
Suggestion createSuggestion(Member suggester, String text, Message message, Long suggestionId, Message commandMessage);
|
||||
Suggestion createSuggestion(AUserInAServer suggester, String text, Message message, Long suggestionId, Message commandMessage);
|
||||
Optional<Suggestion> getSuggestionOptional(Long serverId, Long suggestionId);
|
||||
Suggestion getSuggestion(Long serverId, Long suggestionId);
|
||||
void setSuggestionState(Suggestion suggestion, SuggestionState newState);
|
||||
void deleteSuggestion(Long serverId, Long suggestionId);
|
||||
void deleteSuggestion(List<Suggestion> suggestions);
|
||||
void deleteSuggestion(Suggestion suggestion);
|
||||
List<Suggestion> getSuggestionsUpdatedBeforeNotNew(Instant date);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class InteractiveServiceBean implements InteractiveService {
|
||||
|
||||
@Override
|
||||
public void createMessageWithResponse(MessageToSend messageToSend, AUserInAServer responder, AChannel channel, Long messageId, Consumer<MessageReceivedEvent> action, Runnable finalAction) {
|
||||
channelService.sendMessageToSendToAChannel(messageToSend, channel);
|
||||
channelService.sendMessageEmbedToSendToAChannel(messageToSend, channel);
|
||||
Long userId = responder.getUserReference().getId();
|
||||
eventWaiter.waitForEvent(MessageReceivedEvent.class, event -> {
|
||||
if(event != null) {
|
||||
|
||||
@@ -184,7 +184,7 @@ public class ChannelServiceBean implements ChannelService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CompletableFuture<Message>> sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel) {
|
||||
public List<CompletableFuture<Message>> sendMessageEmbedToSendToAChannel(MessageToSend messageToSend, AChannel channel) {
|
||||
Optional<TextChannel> textChannelFromServer = getTextChannelFromServerOptional(channel.getServer().getId(), channel.getId());
|
||||
if(textChannelFromServer.isPresent()) {
|
||||
return sendMessageToSendToChannel(messageToSend, textChannelFromServer.get());
|
||||
@@ -193,7 +193,7 @@ public class ChannelServiceBean implements ChannelService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Message> sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel, Integer embedIndex) {
|
||||
public CompletableFuture<Message> sendMessageEmbedToSendToAChannel(MessageToSend messageToSend, AChannel channel, Integer embedIndex) {
|
||||
return sendEmbedToAChannel(messageToSend.getEmbeds().get(embedIndex), channel);
|
||||
}
|
||||
|
||||
@@ -244,9 +244,15 @@ public class ChannelServiceBean implements ChannelService {
|
||||
}
|
||||
}
|
||||
Set<Message.MentionType> allowedMentions = getAllowedMentionsFor(textChannel, messageToSend);
|
||||
allMessageActions.forEach(messageAction ->
|
||||
futures.add(messageAction.allowedMentions(allowedMentions).submit())
|
||||
);
|
||||
allMessageActions.forEach(messageAction -> {
|
||||
if(messageToSend.getReferencedMessageId() != null) {
|
||||
messageAction = messageAction.referenceById(messageToSend.getReferencedMessageId());
|
||||
if(messageToSend.getMessageConfig() != null && !messageToSend.getMessageConfig().isMentionsReferencedMessage()) {
|
||||
messageAction = messageAction.mentionRepliedUser(false);
|
||||
}
|
||||
}
|
||||
futures.add(messageAction.allowedMentions(allowedMentions).submit());
|
||||
});
|
||||
return futures;
|
||||
}
|
||||
|
||||
@@ -284,6 +290,9 @@ public class ChannelServiceBean implements ChannelService {
|
||||
throw new IllegalArgumentException("Message to send did not contain anything to send.");
|
||||
}
|
||||
}
|
||||
if(messageToSend.getReferencedMessageId() != null) {
|
||||
messageAction = messageAction.referenceById(messageToSend.getReferencedMessageId());
|
||||
}
|
||||
metricService.incrementCounter(MESSAGE_EDIT_METRIC);
|
||||
return messageAction.submit();
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ public class MessageServiceBean implements MessageService {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Message> createStatusMessage(MessageToSend messageToSend, AChannel channel) {
|
||||
return channelService.sendMessageToSendToAChannel(messageToSend, channel).get(0);
|
||||
return channelService.sendMessageEmbedToSendToAChannel(messageToSend, channel).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -51,6 +51,7 @@ public class EmbedConfiguration {
|
||||
* The {@link OffsetDateTime} object used as the time stamp in the {@link net.dv8tion.jda.api.entities.MessageEmbed}
|
||||
*/
|
||||
private OffsetDateTime timeStamp;
|
||||
private Long referencedMessageId;
|
||||
/**
|
||||
* The message which is posted along the {@link net.dv8tion.jda.api.entities.MessageEmbed} as a normal message.
|
||||
*/
|
||||
|
||||
@@ -16,4 +16,6 @@ public class MetaEmbedConfiguration {
|
||||
private boolean allowsEveryoneMention;
|
||||
@Builder.Default
|
||||
private boolean allowsUserMention = true;
|
||||
@Builder.Default
|
||||
private boolean mentionsReferencedMessage = true;
|
||||
}
|
||||
|
||||
@@ -164,11 +164,13 @@ public class TemplateServiceBean implements TemplateService {
|
||||
log.info("Limiting size of messages. Max allowed: {}, currently: {}.", messageLimit, messages.size());
|
||||
messages.subList(messageLimit.intValue(), messages.size()).clear();
|
||||
}
|
||||
Long referencedMessageId = embedConfiguration.getReferencedMessageId();
|
||||
|
||||
return MessageToSend.builder()
|
||||
.embeds(embeds)
|
||||
.messageConfig(createMessageConfig(embedConfiguration.getMetaConfig()))
|
||||
.messages(messages)
|
||||
.referencedMessageId(referencedMessageId)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -181,6 +183,7 @@ public class TemplateServiceBean implements TemplateService {
|
||||
.allowsEveryoneMention(metaEmbedConfiguration.isAllowsEveryoneMention())
|
||||
.allowsUserMention(metaEmbedConfiguration.isAllowsUserMention())
|
||||
.allowsRoleMention(metaEmbedConfiguration.isAllowsRoleMention())
|
||||
.mentionsReferencedMessage(metaEmbedConfiguration.isMentionsReferencedMessage())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ abstracto.eventWaiter.threads=10
|
||||
server.port=8080
|
||||
|
||||
abstracto.allowedmention.everyone=false
|
||||
abstracto.allowedmention.role=true
|
||||
abstracto.allowedmention.role=false
|
||||
abstracto.allowedmention.user=true
|
||||
|
||||
abstracto.systemConfigs.prefix.name=prefix
|
||||
|
||||
@@ -21,8 +21,8 @@ public interface ChannelService {
|
||||
CompletableFuture<Message> sendEmbedToAChannel(MessageEmbed embed, AChannel channel);
|
||||
CompletableFuture<Message> sendEmbedToChannel(MessageEmbed embed, MessageChannel channel);
|
||||
MessageAction sendEmbedToChannelInComplete(MessageEmbed embed, MessageChannel channel);
|
||||
List<CompletableFuture<Message>> sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel);
|
||||
CompletableFuture<Message> sendMessageToSendToAChannel(MessageToSend messageToSend, AChannel channel, Integer embedIndex);
|
||||
List<CompletableFuture<Message>> sendMessageEmbedToSendToAChannel(MessageToSend messageToSend, AChannel channel);
|
||||
CompletableFuture<Message> sendMessageEmbedToSendToAChannel(MessageToSend messageToSend, AChannel channel, Integer embedIndex);
|
||||
|
||||
CompletableFuture<Message> retrieveMessageInChannel(Long serverId, Long channelId, Long messageId);
|
||||
CompletableFuture<Message> retrieveMessageInChannel(MessageChannel channel, Long messageId);
|
||||
|
||||
@@ -12,4 +12,6 @@ public class MessageConfig {
|
||||
private boolean allowsEveryoneMention;
|
||||
@Builder.Default
|
||||
private boolean allowsUserMention = true;
|
||||
@Builder.Default
|
||||
private boolean mentionsReferencedMessage = true;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public class MessageToSend {
|
||||
*/
|
||||
private File fileToSend;
|
||||
private MessageConfig messageConfig;
|
||||
private Long referencedMessageId;
|
||||
|
||||
public boolean hasFileToSend() {
|
||||
return fileToSend != null;
|
||||
|
||||
@@ -76,13 +76,19 @@ Creating a suggestion::
|
||||
* Usage: `suggest <text>`
|
||||
* Description: Posts the text to the `suggest` post target and places the emotes for up and down voting.
|
||||
Accepting a suggestion::
|
||||
* Usage: `accept <suggestionId> [note]`
|
||||
* Description: Re-posts the suggestion identified by `suggestionId` and marks the suggestion as accepted. The optional `note` will be used in this re-post, if provided.
|
||||
* Usage: `accept <suggestionId> [reason]`
|
||||
* Description: Re-posts the suggestion identified by `suggestionId` and marks the suggestion as accepted. The optional `reason` will be used in this re-post, if provided.
|
||||
* Example: `accept 1 okay` in order to accept the suggestion `1` with the reason `okay`
|
||||
Rejecting a suggestion::
|
||||
* Usage: `reject <suggestionId> [note]`
|
||||
* Description: Re-posts the suggestion identified by `suggestionId` and marks the suggestion as denied. The optional `note` will be used in this re-post, if provided.
|
||||
* Usage: `reject <suggestionId> [reason]`
|
||||
* Description: Re-posts the suggestion identified by `suggestionId` and marks the suggestion as denied. The optional `reason` will be used in this re-post, if provided.
|
||||
* Example: `deny 1 not okay` in order to reject the suggestion `1` with the reason `not okay`
|
||||
Removing a suggestion you created::
|
||||
* Usage: `unSuggest <suggestionId>`
|
||||
* Description: This will delete the suggestion identified by `suggestionId` from the channel and the database, but this is only possible within a specicied time range.
|
||||
Vetoing a suggestion::
|
||||
* Usage : `veto <suggestion> [reason]`
|
||||
* Description: This command will veto the suggestion, this means, it should be indicated that the suggestion was not rejected by votes, but because it was not acceptable on a fundamental level. This is basically just a different state of the suggestion.
|
||||
|
||||
=== Miscellaneous
|
||||
|
||||
|
||||
Reference in New Issue
Block a user