From 7d30afbd2c7b310bbf9dcf93a069c38ad13bf89d Mon Sep 17 00:00:00 2001 From: Sheldan <5037282+Sheldan@users.noreply.github.com> Date: Mon, 24 May 2021 17:39:19 +0200 Subject: [PATCH] [AB-262] adding feature mode to suggestion to be automatically reminded of a suggestion after a configurable amount of time --- .../remind/service/RemindServiceBean.java | 2 +- .../abstracto-modules/suggestion/pom.xml | 7 ++ .../suggestion/job/SuggestionReminderJob.java | 40 +++++++++ .../service/SuggestionServiceBean.java | 88 ++++++++++++++++++- .../migrations/1.2.13/collection.xml | 11 +++ .../migrations/1.2.13/seedData/data.xml | 10 +++ .../1.2.13/seedData/suggestionReminderJob.xml | 18 ++++ .../migrations/1.2.13/tables/suggestion.xml | 15 ++++ .../migrations/1.2.13/tables/tables.xml | 10 +++ .../migrations/suggestion-changeLog.xml | 1 + .../resources/suggestion-config.properties | 10 ++- .../service/SuggestionServiceBeanTest.java | 9 +- .../config/SuggestionFeatureConfig.java | 14 ++- .../config/SuggestionFeatureMode.java | 15 ++++ .../config/SuggestionPostTarget.java | 2 +- .../suggestion/model/database/Suggestion.java | 3 + .../template/SuggestionReminderModel.java | 21 +++++ .../suggestion/service/SuggestionService.java | 5 ++ .../main/docs/asciidoc/modules/utility.adoc | 17 ++-- 19 files changed, 284 insertions(+), 14 deletions(-) create mode 100644 abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/job/SuggestionReminderJob.java create mode 100644 abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/collection.xml create mode 100644 abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/seedData/data.xml create mode 100644 abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/seedData/suggestionReminderJob.xml create mode 100644 abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/tables/suggestion.xml create mode 100644 abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/tables/tables.xml create mode 100644 abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionFeatureMode.java create mode 100644 abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/SuggestionReminderModel.java diff --git a/abstracto-application/abstracto-modules/remind/remind-impl/src/main/java/dev/sheldan/abstracto/remind/service/RemindServiceBean.java b/abstracto-application/abstracto-modules/remind/remind-impl/src/main/java/dev/sheldan/abstracto/remind/service/RemindServiceBean.java index 1a901c763..7beaaf4b6 100644 --- a/abstracto-application/abstracto-modules/remind/remind-impl/src/main/java/dev/sheldan/abstracto/remind/service/RemindServiceBean.java +++ b/abstracto-application/abstracto-modules/remind/remind-impl/src/main/java/dev/sheldan/abstracto/remind/service/RemindServiceBean.java @@ -111,7 +111,7 @@ public class RemindServiceBean implements ReminderService { parameters.put("reminderId", reminder.getId().toString()); JobParameters jobParameters = JobParameters.builder().parameters(parameters).build(); 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); reminderManagementService.saveReminder(reminder); } diff --git a/abstracto-application/abstracto-modules/suggestion/pom.xml b/abstracto-application/abstracto-modules/suggestion/pom.xml index ae63489af..713c0695b 100644 --- a/abstracto-application/abstracto-modules/suggestion/pom.xml +++ b/abstracto-application/abstracto-modules/suggestion/pom.xml @@ -21,6 +21,13 @@ ${project.version} compile + + + dev.sheldan.abstracto.scheduling + scheduling-int + ${project.version} + compile + diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/job/SuggestionReminderJob.java b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/job/SuggestionReminderJob.java new file mode 100644 index 000000000..7b0ec011a --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/job/SuggestionReminderJob.java @@ -0,0 +1,40 @@ +package dev.sheldan.abstracto.suggestion.job; + +import dev.sheldan.abstracto.core.models.ServerSpecificId; +import dev.sheldan.abstracto.suggestion.service.SuggestionService; +import lombok.Getter; +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 +@Getter +@Setter +@PersistJobDataAfterExecution +public class SuggestionReminderJob extends QuartzJobBean { + + @Autowired + private SuggestionService suggestionService; + + private Long suggestionId; + private Long serverId; + + @Override + protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { + log.info("Executing suggestion reminder job for suggestion {} in server {}", suggestionId, serverId); + try { + suggestionService.remindAboutSuggestion(new ServerSpecificId(serverId, suggestionId)); + } catch (Exception exception) { + log.error("Suggestion reminder job failed.", exception); + } + } + +} diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/SuggestionServiceBean.java b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/SuggestionServiceBean.java index 96527f897..4d19c154e 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/SuggestionServiceBean.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/SuggestionServiceBean.java @@ -1,5 +1,8 @@ package dev.sheldan.abstracto.suggestion.service; +import dev.sheldan.abstracto.core.models.ServerChannelMessage; +import dev.sheldan.abstracto.core.models.ServerSpecificId; +import dev.sheldan.abstracto.core.models.ServerUser; import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.service.*; @@ -8,11 +11,16 @@ import dev.sheldan.abstracto.core.service.management.UserInServerManagementServi import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.service.TemplateService; +import dev.sheldan.abstracto.scheduling.model.JobParameters; +import dev.sheldan.abstracto.scheduling.service.SchedulerService; +import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition; +import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureMode; import dev.sheldan.abstracto.suggestion.config.SuggestionPostTarget; 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.model.template.SuggestionReminderModel; import dev.sheldan.abstracto.suggestion.service.management.SuggestionManagementService; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.*; @@ -24,6 +32,8 @@ import org.springframework.transaction.annotation.Transactional; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.HashMap; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -36,6 +46,7 @@ public class SuggestionServiceBean implements SuggestionService { public static final String SUGGESTION_YES_EMOTE = "suggestionYes"; public static final String SUGGESTION_NO_EMOTE = "suggestionNo"; public static final String SUGGESTION_COUNTER_KEY = "suggestion"; + public static final String SUGGESTION_REMINDER_TEMPLATE_KEY = "suggest_suggestion_reminder"; @Autowired private SuggestionManagementService suggestionManagementService; @@ -73,6 +84,15 @@ public class SuggestionServiceBean implements SuggestionService { @Autowired private UserService userService; + @Autowired + private SchedulerService schedulerService; + + @Autowired + private FeatureModeService featureModeService; + + @Autowired + private ConfigService configService; + @Value("${abstracto.feature.suggestion.removalMaxAge}") private Long removalMaxAgeSeconds; @@ -114,8 +134,25 @@ public class SuggestionServiceBean implements SuggestionService { @Transactional 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, commandMessage); + Long serverId = member.getGuild().getIdLong(); + log.info("Persisting suggestion {} for server {} in database.", suggestionId, serverId); + Suggestion suggestion = suggestionManagementService.createSuggestion(member, text, message, suggestionId, commandMessage); + if(featureModeService.featureModeActive(SuggestionFeatureDefinition.SUGGEST, serverId, SuggestionFeatureMode.SUGGESTION_REMINDER)) { + String triggerKey = scheduleSuggestionReminder(serverId, suggestionId); + suggestion.setSuggestionReminderJobTriggerKey(triggerKey); + } + } + + private String scheduleSuggestionReminder(Long serverId, Long suggestionId) { + HashMap parameters = new HashMap<>(); + parameters.put("serverId", serverId.toString()); + parameters.put("suggestionId", suggestionId.toString()); + JobParameters jobParameters = JobParameters.builder().parameters(parameters).build(); + Long days = configService.getLongValueOrConfigDefault(SuggestionService.SUGGESTION_REMINDER_DAYS_CONFIG_KEY, serverId); + Instant targetDate = Instant.now().plus(days, ChronoUnit.DAYS); + String triggerKey = schedulerService.executeJobWithParametersOnce("suggestionReminderJob", "suggestion", jobParameters, Date.from(targetDate)); + log.info("Starting scheduled job with trigger {} to execute suggestion reminder in server {} for suggestion {}.", triggerKey, serverId, suggestionId); + return triggerKey; } @Override @@ -123,6 +160,7 @@ public class SuggestionServiceBean implements SuggestionService { Long serverId = commandMessage.getGuild().getIdLong(); Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId); suggestionManagementService.setSuggestionState(suggestion, SuggestionState.ACCEPTED); + cancelSuggestionReminder(suggestion); log.info("Accepting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId()); return updateSuggestion(commandMessage.getMember(), text, suggestion); } @@ -132,6 +170,7 @@ public class SuggestionServiceBean implements SuggestionService { Long serverId = commandMessage.getGuild().getIdLong(); Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId); suggestionManagementService.setSuggestionState(suggestion, SuggestionState.VETOED); + cancelSuggestionReminder(suggestion); log.info("Vetoing suggestion {} in server {}.", suggestionId, suggestion.getServer().getId()); return updateSuggestion(commandMessage.getMember(), text, suggestion); } @@ -186,6 +225,7 @@ public class SuggestionServiceBean implements SuggestionService { Long serverId = commandMessage.getGuild().getIdLong(); Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId); suggestionManagementService.setSuggestionState(suggestion, SuggestionState.REJECTED); + cancelSuggestionReminder(suggestion); log.info("Rejecting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId()); return updateSuggestion(commandMessage.getMember(), text, suggestion); } @@ -213,8 +253,50 @@ public class SuggestionServiceBean implements SuggestionService { suggestionManagementService.deleteSuggestion(suggestionsToRemove); } + @Override + @Transactional + public CompletableFuture remindAboutSuggestion(ServerSpecificId suggestionId) { + Long serverId = suggestionId.getServerId(); + Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId.getId()); + ServerChannelMessage suggestionServerChannelMessage = ServerChannelMessage + .builder() + .serverId(serverId) + .channelId(suggestion.getChannel().getId()) + .messageId(suggestion.getMessageId()) + .build(); + ServerChannelMessage commandServerChannelMessage = ServerChannelMessage + .builder() + .serverId(serverId) + .channelId(suggestion.getCommandChannel().getId()) + .messageId(suggestion.getCommandMessageId()) + .build(); + SuggestionReminderModel model = SuggestionReminderModel + .builder() + .serverId(serverId) + .serverUser(ServerUser.fromAUserInAServer(suggestion.getSuggester())) + .suggestionCreationDate(suggestion.getCreated()) + .suggestionId(suggestionId.getId()) + .suggestionMessage(suggestionServerChannelMessage) + .suggestionCommandMessage(commandServerChannelMessage) + .build(); + MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_REMINDER_TEMPLATE_KEY, model, serverId); + log.info("Reminding about suggestion {} in server {}.", suggestionId.getId(), serverId); + List> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, serverId); + return FutureUtils.toSingleFutureGeneric(completableFutures); + } + + @Override + public void cancelSuggestionReminder(Suggestion suggestion) { + if(suggestion.getSuggestionReminderJobTriggerKey() != null) { + log.info("Cancelling reminder for suggestion {} in server {}.", suggestion.getSuggestionId().getId(), suggestion.getSuggestionId().getServerId()); + schedulerService.stopTrigger(suggestion.getSuggestionReminderJobTriggerKey()); + } + } + @Transactional public void deleteSuggestion(Long suggestionId, Long serverId) { - suggestionManagementService.deleteSuggestion(serverId, suggestionId); + Suggestion suggestion = suggestionManagementService.getSuggestion(serverId, suggestionId); + cancelSuggestionReminder(suggestion); + suggestionManagementService.deleteSuggestion(suggestion); } } diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/collection.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/collection.xml new file mode 100644 index 000000000..4cd75ecab --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/collection.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/seedData/data.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/seedData/data.xml new file mode 100644 index 000000000..c039b7e9d --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/seedData/data.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/seedData/suggestionReminderJob.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/seedData/suggestionReminderJob.xml new file mode 100644 index 000000000..100ebab2f --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/seedData/suggestionReminderJob.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/tables/suggestion.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/tables/suggestion.xml new file mode 100644 index 000000000..c5c4e4afa --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/tables/suggestion.xml @@ -0,0 +1,15 @@ + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/tables/tables.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/tables/tables.xml new file mode 100644 index 000000000..17a0eb835 --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.2.13/tables/tables.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/suggestion-changeLog.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/suggestion-changeLog.xml index 8561a5b49..cd0585c7c 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/suggestion-changeLog.xml +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/suggestion-changeLog.xml @@ -8,4 +8,5 @@ http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" > + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/suggestion-config.properties b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/suggestion-config.properties index 8bafbd043..f895c5c2b 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/suggestion-config.properties +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/suggestion-config.properties @@ -2,6 +2,14 @@ abstracto.featureFlags.suggestion.featureName=suggestion abstracto.featureFlags.suggestion.enabled=false abstracto.postTargets.suggestions.name=suggestions +abstracto.postTargets.suggestionReminder.name=suggestionReminder abstracto.feature.suggestion.removalMaxAge=3600 -abstracto.feature.suggestion.removalDays=2 \ No newline at end of file +abstracto.feature.suggestion.removalDays=2 + +abstracto.featureModes.suggestionReminder.featureName=suggestion +abstracto.featureModes.suggestionReminder.mode=suggestionReminder +abstracto.featureModes.suggestionReminder.enabled=false + +abstracto.systemConfigs.suggestionReminderDays.name=suggestionReminderDays +abstracto.systemConfigs.suggestionReminderDays.longValue=7 \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/test/java/dev/sheldan/abstracto/suggestion/service/SuggestionServiceBeanTest.java b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/test/java/dev/sheldan/abstracto/suggestion/service/SuggestionServiceBeanTest.java index 644044121..e60cc41d7 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/test/java/dev/sheldan/abstracto/suggestion/service/SuggestionServiceBeanTest.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/test/java/dev/sheldan/abstracto/suggestion/service/SuggestionServiceBeanTest.java @@ -11,9 +11,10 @@ import dev.sheldan.abstracto.core.service.management.ServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.templating.model.MessageToSend; import dev.sheldan.abstracto.core.templating.service.TemplateService; +import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureDefinition; +import dev.sheldan.abstracto.suggestion.config.SuggestionFeatureMode; import dev.sheldan.abstracto.suggestion.config.SuggestionPostTarget; import dev.sheldan.abstracto.suggestion.exception.SuggestionNotFoundException; -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; @@ -76,6 +77,9 @@ public class SuggestionServiceBeanTest { @Mock private ServerManagementService serverManagementService; + @Mock + private FeatureModeService featureModeService; + @Mock private UserService userService; @@ -125,10 +129,11 @@ public class SuggestionServiceBeanTest { @Test public void testCreateSuggestion() { when(member.getGuild()).thenReturn(guild); - when(guild.getId()).thenReturn("5"); + when(guild.getIdLong()).thenReturn(SERVER_ID); String text = "text"; Message message = Mockito.mock(Message.class); Message commandMessage = Mockito.mock(Message.class); + when(featureModeService.featureModeActive(SuggestionFeatureDefinition.SUGGEST, SERVER_ID, SuggestionFeatureMode.SUGGESTION_REMINDER)).thenReturn(false); testUnit.persistSuggestionInDatabase(member, text, message, SUGGESTION_ID, commandMessage); verify(suggestionManagementService, times(1)).createSuggestion(member, text, message, SUGGESTION_ID, commandMessage); } diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionFeatureConfig.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionFeatureConfig.java index 79276e490..142648f50 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionFeatureConfig.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionFeatureConfig.java @@ -2,7 +2,9 @@ package dev.sheldan.abstracto.suggestion.config; import dev.sheldan.abstracto.core.config.FeatureConfig; import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.config.FeatureMode; import dev.sheldan.abstracto.core.config.PostTargetEnum; +import dev.sheldan.abstracto.suggestion.service.SuggestionService; import org.springframework.stereotype.Component; import java.util.Arrays; @@ -18,11 +20,21 @@ public class SuggestionFeatureConfig implements FeatureConfig { @Override public List getRequiredPostTargets() { - return Arrays.asList(SuggestionPostTarget.SUGGESTION); + return Arrays.asList(SuggestionPostTarget.SUGGESTION, SuggestionPostTarget.SUGGESTION_REMINDER); } @Override public List getRequiredEmotes() { return Arrays.asList("suggestionYes", "suggestionNo"); } + + @Override + public List getAvailableModes() { + return Arrays.asList(SuggestionFeatureMode.SUGGESTION_REMINDER); + } + + @Override + public List getRequiredSystemConfigKeys() { + return Arrays.asList(SuggestionService.SUGGESTION_REMINDER_DAYS_CONFIG_KEY); + } } diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionFeatureMode.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionFeatureMode.java new file mode 100644 index 000000000..80ed7de31 --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionFeatureMode.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.suggestion.config; + +import dev.sheldan.abstracto.core.config.FeatureMode; +import lombok.Getter; + +@Getter +public enum SuggestionFeatureMode implements FeatureMode { + SUGGESTION_REMINDER("suggestionReminder"); + + private final String key; + + SuggestionFeatureMode(String key) { + this.key = key; + } +} diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionPostTarget.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionPostTarget.java index a45ee976e..717ed3c3f 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionPostTarget.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/config/SuggestionPostTarget.java @@ -5,7 +5,7 @@ import lombok.Getter; @Getter public enum SuggestionPostTarget implements PostTargetEnum { - SUGGESTION("suggestions"); + SUGGESTION("suggestions"), SUGGESTION_REMINDER("suggestionReminder"); private String key; diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/database/Suggestion.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/database/Suggestion.java index d6a72bf9a..0e55bcad4 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/database/Suggestion.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/database/Suggestion.java @@ -66,4 +66,7 @@ public class Suggestion implements Serializable { @Column(name = "command_message_id") private Long commandMessageId; + @Column(name = "job_trigger_key") + private String suggestionReminderJobTriggerKey; + } diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/SuggestionReminderModel.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/SuggestionReminderModel.java new file mode 100644 index 000000000..a3b95ac95 --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/SuggestionReminderModel.java @@ -0,0 +1,21 @@ +package dev.sheldan.abstracto.suggestion.model.template; + +import dev.sheldan.abstracto.core.models.ServerChannelMessage; +import dev.sheldan.abstracto.core.models.ServerUser; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.time.Instant; + +@Getter +@Setter +@Builder +public class SuggestionReminderModel { + private Long serverId; + private Long suggestionId; + private Instant suggestionCreationDate; + private ServerChannelMessage suggestionMessage; + private ServerChannelMessage suggestionCommandMessage; + private ServerUser serverUser; +} diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/SuggestionService.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/SuggestionService.java index 0f0a90dae..1075c4b3b 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/SuggestionService.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/SuggestionService.java @@ -1,15 +1,20 @@ package dev.sheldan.abstracto.suggestion.service; +import dev.sheldan.abstracto.core.models.ServerSpecificId; +import dev.sheldan.abstracto.suggestion.model.database.Suggestion; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; import java.util.concurrent.CompletableFuture; public interface SuggestionService { + String SUGGESTION_REMINDER_DAYS_CONFIG_KEY = "suggestionReminderDays"; CompletableFuture createSuggestionMessage(Message commandMessage, String text); CompletableFuture acceptSuggestion(Long suggestionId, Message commandMessage, String text); CompletableFuture vetoSuggestion(Long suggestionId, Message commandMessage, String text); CompletableFuture rejectSuggestion(Long suggestionId, Message commandMessage, String text); CompletableFuture removeSuggestion(Long suggestionId, Member member); void cleanUpSuggestions(); + CompletableFuture remindAboutSuggestion(ServerSpecificId suggestionId); + void cancelSuggestionReminder(Suggestion suggestion); } diff --git a/abstracto-application/documentation/src/main/docs/asciidoc/modules/utility.adoc b/abstracto-application/documentation/src/main/docs/asciidoc/modules/utility.adoc index ef003ea50..53280d46d 100644 --- a/abstracto-application/documentation/src/main/docs/asciidoc/modules/utility.adoc +++ b/abstracto-application/documentation/src/main/docs/asciidoc/modules/utility.adoc @@ -64,31 +64,38 @@ This feature provides the ability for members to post suggestions containing tex Feature key: `suggestion` +==== Feature modes +`suggestionReminder`:: If this is enabled, a message will be sent to the post target `suggestionReminder`, after the amount of days configured in `suggestionReminderDays`. Disabled by default. + ==== Post targets `suggestions`:: the target of the messages containing the suggestions +`suggestionReminder`:: the target for the message to remind about suggestions. Requires feature mode `suggestionReminder` to be enabled ==== Emotes * `suggestionYes` for up-voting a suggestion * `suggestionNo` for down-voting a suggestion +==== Relevant system configuration +`suggestionReminderDays` The amount of days in which the reminder, from feature mode `suggestionReminder`, should be posted in. Default: 7 + ==== Commands Creating a suggestion:: * Usage: `suggest ` -* Description: Posts the text to the `suggest` post target and places the emotes for up and down voting. +* Description: Posts the text to the `suggest` post target and places the emotes for up and down voting. If `suggestionReminder` is enabled, this will create a suggestion reminder. Accepting a suggestion:: * Usage: `accept [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. +* 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. This will cancel the suggestion reminder (if it exists) * Example: `accept 1 okay` in order to accept the suggestion `1` with the reason `okay` Rejecting a suggestion:: * Usage: `reject [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. +* 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. This will cancel the suggestion reminder (if it exists) * Example: `deny 1 not okay` in order to reject the suggestion `1` with the reason `not okay` Removing a suggestion you created:: * Usage: `unSuggest ` -* 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. +* Description: This will delete the suggestion identified by `suggestionId` from the channel and the database, but this is only possible within a specified time range. This will cancel the suggestion reminder (if it exists) Vetoing a suggestion:: * Usage : `veto [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. +* 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. This will cancel the suggestion reminder (if it exists) === Miscellaneous