diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/pom.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/pom.xml index 0ca4779c8..b34c49f6e 100644 --- a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/pom.xml +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/pom.xml @@ -9,11 +9,6 @@ entertainment-impl - - 8 - 8 - - @@ -57,6 +52,12 @@ test + + dev.sheldan.abstracto.scheduling + scheduling-int + ${project.version} + + com.google.code.gson gson diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/command/PressFCommand.java b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/command/PressFCommand.java new file mode 100644 index 000000000..7b54309e2 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/command/PressFCommand.java @@ -0,0 +1,140 @@ +package dev.sheldan.abstracto.entertainment.command; + +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.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.interaction.InteractionService; +import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig; +import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.service.ConfigService; +import dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.core.utils.ParseUtils; +import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition; +import dev.sheldan.abstracto.entertainment.config.EntertainmentModuleDefinition; +import dev.sheldan.abstracto.entertainment.config.EntertainmentSlashCommandNames; +import dev.sheldan.abstracto.entertainment.model.command.PressFPromptModel; +import dev.sheldan.abstracto.entertainment.service.EntertainmentService; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import static dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig.PRESS_F_DEFAULT_DURATION_SECONDS; + +@Component +public class PressFCommand extends AbstractConditionableCommand { + + public static final String TEXT_PARAMETER = "text"; + public static final String DURATION_PARAMETER = "duration"; + + private static final String RESPONSE_TEMPLATE = "pressF_response"; + public static final String PRESS_F_COMMAND_NAME = "pressF"; + + @Autowired + private InteractionService interactionService; + + @Autowired + private SlashCommandParameterService slashCommandParameterService; + + @Autowired + private ConfigService configService; + + @Autowired + private EntertainmentService entertainmentService; + + @Autowired + private ChannelService channelService; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + String text = (String) commandContext.getParameters().getParameters().get(0); + Long defaultDurationSeconds = configService.getLongValueOrConfigDefault(PRESS_F_DEFAULT_DURATION_SECONDS, commandContext.getGuild().getIdLong()); + Duration duration = Duration.ofSeconds(defaultDurationSeconds); + PressFPromptModel pressFModel = entertainmentService.getPressFModel(text); + List> messages = channelService.sendEmbedTemplateInMessageChannelList(RESPONSE_TEMPLATE, pressFModel, commandContext.getChannel()); + return FutureUtils.toSingleFutureGeneric(messages) + .thenAccept(unused -> entertainmentService.persistPressF(text, duration, commandContext.getAuthor(), + pressFModel.getPressFComponentId(), commandContext.getChannel(), messages.get(0).join().getIdLong())) + .thenApply(unused -> CommandResult.fromSuccess()); + } + + @Override + public CompletableFuture executeSlash(SlashCommandInteractionEvent event) { + String text = slashCommandParameterService.getCommandOption(TEXT_PARAMETER, event, String.class); + Duration duration; + if(slashCommandParameterService.hasCommandOption(DURATION_PARAMETER, event)) { + String durationString = slashCommandParameterService.getCommandOption(DURATION_PARAMETER, event, String.class); + duration = ParseUtils.parseDuration(durationString); + } else { + Long defaultDurationSeconds = configService.getLongValueOrConfigDefault(PRESS_F_DEFAULT_DURATION_SECONDS, event.getGuild().getIdLong()); + duration = Duration.ofSeconds(defaultDurationSeconds); + } + PressFPromptModel pressFModel = entertainmentService.getPressFModel(text); + return interactionService.replyEmbed(RESPONSE_TEMPLATE, pressFModel, event) + .thenCompose(interactionHook -> interactionHook.retrieveOriginal().submit()) + .thenAccept(message -> { + entertainmentService.persistPressF(text, duration, event.getMember(), pressFModel.getPressFComponentId(), event.getGuildChannel(), message.getIdLong()); + }) + .thenApply(unused -> CommandResult.fromSuccess()); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + Parameter textParameter = Parameter + .builder() + .name(TEXT_PARAMETER) + .type(String.class) + .templated(true) + .remainder(true) + .build(); + parameters.add(textParameter); + Parameter durationParameter = Parameter + .builder() + .name(DURATION_PARAMETER) + .type(Duration.class) + .slashCommandOnly(true) + .optional(true) + .templated(true) + .build(); + parameters.add(durationParameter); + HelpInfo helpInfo = HelpInfo + .builder() + .templated(true) + .build(); + + SlashCommandConfig slashCommandConfig = SlashCommandConfig + .builder() + .enabled(true) + .rootCommandName(EntertainmentSlashCommandNames.ENTERTAINMENT) + .commandName("pressf") + .build(); + + return CommandConfiguration.builder() + .name(PRESS_F_COMMAND_NAME) + .module(EntertainmentModuleDefinition.ENTERTAINMENT) + .templated(true) + .causesReaction(false) + .async(true) + .slashCommandConfig(slashCommandConfig) + .supportsEmbedException(true) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureDefinition getFeature() { + return EntertainmentFeatureDefinition.ENTERTAINMENT; + } +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/job/PressFEvaluationJob.java b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/job/PressFEvaluationJob.java new file mode 100644 index 000000000..1b9a7f968 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/job/PressFEvaluationJob.java @@ -0,0 +1,35 @@ +package dev.sheldan.abstracto.entertainment.job; + +import dev.sheldan.abstracto.entertainment.service.EntertainmentService; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +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 PressFEvaluationJob extends QuartzJobBean { + @Getter + @Setter + private Long pressFId; + + @Autowired + private EntertainmentService entertainmentService; + + @Override + protected void executeInternal(JobExecutionContext context) { + try { + log.info("Executing press f evaluation job for pressf instance {}.", pressFId); + entertainmentService.evaluatePressF(pressFId); + } catch (Exception exception) { + log.error("Press f evaluation job failed.", exception); + } + } +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/listener/interaction/PressFClickedListener.java b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/listener/interaction/PressFClickedListener.java new file mode 100644 index 000000000..4cfc2f3e6 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/listener/interaction/PressFClickedListener.java @@ -0,0 +1,107 @@ +package dev.sheldan.abstracto.entertainment.listener.interaction; + +import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.config.ListenerPriority; +import dev.sheldan.abstracto.core.interaction.InteractionService; +import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListener; +import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListenerModel; +import dev.sheldan.abstracto.core.interaction.button.listener.ButtonClickedListenerResult; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.models.template.display.MemberDisplay; +import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; +import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureDefinition; +import dev.sheldan.abstracto.entertainment.exception.AlreadyPressedFException; +import dev.sheldan.abstracto.entertainment.model.PressFPayload; +import dev.sheldan.abstracto.entertainment.model.command.PressFJoinModel; +import dev.sheldan.abstracto.entertainment.model.database.PressF; +import dev.sheldan.abstracto.entertainment.service.EntertainmentServiceBean; +import dev.sheldan.abstracto.entertainment.service.management.PressFManagementService; +import dev.sheldan.abstracto.entertainment.service.management.PressFPresserManagementServiceBean; +import jakarta.transaction.Transactional; +import lombok.extern.slf4j.Slf4j; +import net.dv8tion.jda.api.entities.Member; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +@Component +@Slf4j +public class PressFClickedListener implements ButtonClickedListener { + + private static final String PRESS_F_CLICK_RESPONSE_TEMPLATE_KEY = "pressF_join"; + + @Autowired + private PressFPresserManagementServiceBean pressFPresserManagementServiceBean; + + @Autowired + private PressFManagementService pressFManagementService; + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Autowired + private InteractionService interactionService; + + @Autowired + private PressFClickedListener self; + + @Override + public Boolean handlesEvent(ButtonClickedListenerModel model) { + return EntertainmentServiceBean.PRESS_F_BUTTON_ORIGIN.equals(model.getOrigin()); + } + + @Override + public ButtonClickedListenerResult execute(ButtonClickedListenerModel model) { + PressFPayload payload = (PressFPayload) model.getDeserializedPayload(); + Optional pressFOptional = pressFManagementService.getPressFById(payload.getPressFId()); + pressFOptional.ifPresent(pressF -> { + Member presserMember = model.getEvent().getMember(); + AUserInAServer presser = userInServerManagementService.loadOrCreateUser(presserMember); + Long userInServerId = presser.getUserInServerId(); + if(!pressFPresserManagementServiceBean.didUserAlreadyPress(pressF, presser)) { + PressFJoinModel joinModel = PressFJoinModel + .builder() + .messageId(pressF.getMessageId()) + .memberDisplay(MemberDisplay.fromMember(presserMember)) + .build(); + interactionService.replyEmbed(PRESS_F_CLICK_RESPONSE_TEMPLATE_KEY, joinModel, model.getEvent().getInteraction()).thenAccept(interactionHook -> { + self.persistPresser(payload.getPressFId(), userInServerId); + log.info("Send message about pressing to user {} for pressF {}.", presserMember.getIdLong(), payload.getPressFId()); + }).exceptionally(throwable -> { + log.error("Failed to send message or persist press user {} in pressF {}.", presserMember.getIdLong(), payload.getPressFId(), throwable); + return null; + }); + } else { + log.debug("User {} already pressed for pressF {}.", presserMember.getIdLong(), payload.getPressFId()); + throw new AlreadyPressedFException(); + } + }); + return ButtonClickedListenerResult.ACKNOWLEDGED; + } + + @Transactional + public void persistPresser(Long pressFId, Long userInServerId) { + log.info("Persisting pressing of user {} for pressF {}.", userInServerId, pressFId); + AUserInAServer presser = userInServerManagementService.loadOrCreateUser(userInServerId); + Optional pressFByIdOptional = pressFManagementService.getPressFById(pressFId); + pressFByIdOptional.ifPresent(pressF -> { + pressFPresserManagementServiceBean.addPresser(pressF, presser); + }); + } + + @Override + public FeatureDefinition getFeature() { + return EntertainmentFeatureDefinition.ENTERTAINMENT; + } + + @Override + public Integer getPriority() { + return ListenerPriority.MEDIUM; + } + + @Override + public Boolean autoAcknowledgeEvent() { + return false; + } +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/model/PressFPayload.java b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/model/PressFPayload.java new file mode 100644 index 000000000..2b36ce854 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/model/PressFPayload.java @@ -0,0 +1,11 @@ +package dev.sheldan.abstracto.entertainment.model; + +import dev.sheldan.abstracto.core.interaction.button.ButtonPayload; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class PressFPayload implements ButtonPayload { + private Long pressFId; +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/repository/PressFPresserRepository.java b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/repository/PressFPresserRepository.java new file mode 100644 index 000000000..e1353332c --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/repository/PressFPresserRepository.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.entertainment.repository; + +import dev.sheldan.abstracto.entertainment.model.database.PressFPresser; +import dev.sheldan.abstracto.entertainment.model.database.embed.PressFPresserId; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PressFPresserRepository extends JpaRepository { +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/repository/PressFRepository.java b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/repository/PressFRepository.java new file mode 100644 index 000000000..8a8cd87e3 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/repository/PressFRepository.java @@ -0,0 +1,9 @@ +package dev.sheldan.abstracto.entertainment.repository; + +import dev.sheldan.abstracto.entertainment.model.database.PressF; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface PressFRepository extends JpaRepository { +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/EntertainmentServiceBean.java b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/EntertainmentServiceBean.java index 150f4ef92..3c9c2668c 100644 --- a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/EntertainmentServiceBean.java +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/EntertainmentServiceBean.java @@ -2,12 +2,33 @@ package dev.sheldan.abstracto.entertainment.service; import com.google.gson.Gson; import com.google.gson.stream.JsonReader; +import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException; +import dev.sheldan.abstracto.core.interaction.ComponentPayloadService; +import dev.sheldan.abstracto.core.interaction.ComponentService; +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ConfigService; +import dev.sheldan.abstracto.core.service.MessageService; +import dev.sheldan.abstracto.core.service.management.ChannelManagementService; +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.core.utils.FutureUtils; import dev.sheldan.abstracto.entertainment.config.EntertainmentFeatureConfig; import dev.sheldan.abstracto.entertainment.exception.ReactDuplicateCharacterException; +import dev.sheldan.abstracto.entertainment.model.PressFPayload; import dev.sheldan.abstracto.entertainment.model.ReactMapping; +import dev.sheldan.abstracto.entertainment.model.command.PressFPromptModel; +import dev.sheldan.abstracto.entertainment.model.command.PressFResultModel; +import dev.sheldan.abstracto.entertainment.model.database.PressF; +import dev.sheldan.abstracto.entertainment.service.management.PressFManagementService; +import dev.sheldan.abstracto.scheduling.model.JobParameters; +import dev.sheldan.abstracto.scheduling.service.SchedulerService; +import jakarta.transaction.Transactional; import lombok.extern.slf4j.Slf4j; import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; @@ -17,7 +38,10 @@ import javax.annotation.PostConstruct; import java.io.IOException; import java.io.InputStreamReader; import java.security.SecureRandom; +import java.time.Duration; +import java.time.Instant; import java.util.*; +import java.util.concurrent.CompletableFuture; @Component @Slf4j @@ -30,6 +54,9 @@ public class EntertainmentServiceBean implements EntertainmentService { "DONT_COUNT", "REPLY_NO", "SOURCES_NO", "OUTLOOK_NOT_GOOD", "DOUBTFUL" // negative ); + public static final String PRESS_F_BUTTON_ORIGIN = "PRESS_F_BUTTON"; + private static final String PRESS_F_RESULT_TEMPLATE_KEY = "pressF_result"; + private ReactMapping reactMapping; @Autowired @@ -38,6 +65,33 @@ public class EntertainmentServiceBean implements EntertainmentService { @Autowired private ConfigService configService; + @Autowired + private ComponentService componentService; + + @Autowired + private PressFManagementService pressFManagementService; + + @Autowired + private UserInServerManagementService userInServerManagementService; + + @Autowired + private SchedulerService schedulerService; + + @Autowired + private ComponentPayloadService componentPayloadService; + + @Autowired + private ChannelManagementService channelManagementService; + + @Autowired + private ChannelService channelService; + + @Autowired + private TemplateService templateService; + + @Autowired + private MessageService messageService; + @Value("classpath:react_mappings.json") private Resource reactMappingSource; @@ -91,6 +145,66 @@ public class EntertainmentServiceBean implements EntertainmentService { return sb.toString(); } + @Override + public PressFPromptModel getPressFModel(String text) { + String pressFComponent = componentService.generateComponentId(); + return PressFPromptModel + .builder() + .pressFComponentId(pressFComponent) + .text(text) + .build(); + } + + @Transactional + public void persistPressF(String text, Duration duration, Member executingMember, String componentId, GuildMessageChannel guildMessageChannel, Long messageId) { + Instant targetDate = Instant.now().plus(duration); + log.info("Persisting pressF started by {} in server {} with due date {}.", executingMember.getIdLong(), executingMember.getGuild().getIdLong(), targetDate); + AUserInAServer creator = userInServerManagementService.loadOrCreateUser(executingMember); + AChannel channel = channelManagementService.loadChannel(guildMessageChannel); + PressF pressF = pressFManagementService.createPressF(text, targetDate, creator, channel, messageId); + HashMap parameters = new HashMap<>(); + parameters.put("pressFId", pressF.getId().toString()); + JobParameters jobParameters = JobParameters + .builder() + .parameters(parameters) + .build(); + log.debug("Starting scheduled job for pressF {}", pressF.getId()); + schedulerService.executeJobWithParametersOnce("pressFEvaluationJob", "entertainment", jobParameters, Date.from(targetDate)); + PressFPayload pressFPayload = PressFPayload + .builder() + .pressFId(pressF.getId()) + .build(); + log.debug("Persisting payload for pressF {}", pressF.getId()); + componentPayloadService.createButtonPayload(componentId, pressFPayload, PRESS_F_BUTTON_ORIGIN, creator.getServerReference()); + } + + @Override + @Transactional + public CompletableFuture evaluatePressF(Long pressFId) { + Optional pressFOptional = pressFManagementService.getPressFById(pressFId); + if(pressFOptional.isPresent()) { + log.info("Evaluating pressF with id {}", pressFId); + PressF pressF = pressFOptional.get(); + PressFResultModel model = PressFResultModel + .builder() + .userCount((long) pressF.getPresser().size()) + .text(pressF.getText()) + .messageId(pressF.getMessageId()) + .build(); + MessageToSend messageToSend = templateService.renderEmbedTemplate(PRESS_F_RESULT_TEMPLATE_KEY, model); + Long serverId = pressF.getServer().getId(); + Long channelId = pressF.getPressFChannel().getId(); + Long messageId = pressF.getMessageId(); + return FutureUtils.toSingleFutureGeneric(channelService.sendMessageEmbedToSendToAChannel(messageToSend, pressF.getPressFChannel())) + .thenCompose(unused -> messageService.loadMessage(serverId, channelId, messageId).thenCompose(message -> { + log.info("Clearing buttons from pressF {} in with message {} in channel {} in server {}.", pressFId, pressFId, channelId, serverId); + return componentService.clearButtons(message); + })); + } else { + throw new AbstractoRunTimeException(String.format("PressF with id %s not found.", pressFId)); + } + } + @Override public List convertTextToEmojis(String text) { return convertTextToEmojis(text, false); diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFManagementServiceBean.java b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFManagementServiceBean.java new file mode 100644 index 000000000..d5201c65a --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFManagementServiceBean.java @@ -0,0 +1,36 @@ +package dev.sheldan.abstracto.entertainment.service.management; + +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.entertainment.model.database.PressF; +import dev.sheldan.abstracto.entertainment.repository.PressFRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.Optional; + +@Component +public class PressFManagementServiceBean implements PressFManagementService { + + @Autowired + private PressFRepository pressFRepository; + @Override + public PressF createPressF(String text, Instant targetDate, AUserInAServer creator, AChannel channel, Long messageId) { + PressF pressF = PressF + .builder() + .server(creator.getServerReference()) + .creator(creator) + .messageId(messageId) + .pressFChannel(channel) + .text(text) + .targetDate(targetDate) + .build(); + return pressFRepository.save(pressF); + } + + @Override + public Optional getPressFById(Long pressFId) { + return pressFRepository.findById(pressFId); + } +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFPresserManagementServiceBean.java b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFPresserManagementServiceBean.java new file mode 100644 index 000000000..ff5bb35a2 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFPresserManagementServiceBean.java @@ -0,0 +1,32 @@ +package dev.sheldan.abstracto.entertainment.service.management; + +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.entertainment.model.database.PressF; +import dev.sheldan.abstracto.entertainment.model.database.PressFPresser; +import dev.sheldan.abstracto.entertainment.model.database.embed.PressFPresserId; +import dev.sheldan.abstracto.entertainment.repository.PressFPresserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class PressFPresserManagementServiceBean implements PressFPresserManagementService { + + @Autowired + private PressFPresserRepository repository; + + @Override + public PressFPresser addPresser(PressF pressF, AUserInAServer presser) { + PressFPresser pressFPresser = PressFPresser + .builder() + .presser(presser) + .id(new PressFPresserId(presser.getUserInServerId(), pressF.getId())) + .build(); + return repository.save(pressFPresser); + } + + @Override + public boolean didUserAlreadyPress(PressF pressF, AUserInAServer aUserInAServer) { + return repository.existsById(new PressFPresserId(aUserInAServer.getUserInServerId(), pressF.getId())); + } + +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/entertainment-config.properties b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/entertainment-config.properties index 3863d0379..3c90f5988 100644 --- a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/entertainment-config.properties +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/entertainment-config.properties @@ -4,6 +4,9 @@ abstracto.systemConfigs.rouletteBullets.longValue=6 abstracto.systemConfigs.rollDefaultHigh.name=rollDefaultHigh abstracto.systemConfigs.rollDefaultHigh.longValue=6 +abstracto.systemConfigs.pressFDefaultDurationSeconds.name=pressFDefaultDurationSeconds +abstracto.systemConfigs.pressFDefaultDurationSeconds.longValue=90 + abstracto.featureFlags.entertainment.featureName=entertainment abstracto.featureFlags.entertainment.enabled=false diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/collection.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/collection.xml new file mode 100644 index 000000000..30263db2b --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/collection.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/seedData/command.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/seedData/command.xml new file mode 100644 index 000000000..8ef02c48b --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/seedData/command.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/seedData/data.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/seedData/data.xml new file mode 100644 index 000000000..d32fbf858 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/seedData/data.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/seedData/press_f_evaluation_job.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/seedData/press_f_evaluation_job.xml new file mode 100644 index 000000000..bdeca172c --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/seedData/press_f_evaluation_job.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/tables/press_f.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/tables/press_f.xml new file mode 100644 index 000000000..c71e0670f --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/tables/press_f.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DROP TRIGGER IF EXISTS press_f_update_trigger ON press_f; + CREATE TRIGGER press_f_update_trigger BEFORE UPDATE ON press_f FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure(); + + + DROP TRIGGER IF EXISTS press_f_insert_trigger ON press_f; + CREATE TRIGGER press_f_insert_trigger BEFORE INSERT ON press_f FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure(); + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/tables/press_f_presser.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/tables/press_f_presser.xml new file mode 100644 index 000000000..28d9e2f0c --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/tables/press_f_presser.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + DROP TRIGGER IF EXISTS press_f_presser_update_trigger ON press_f_presser; + CREATE TRIGGER press_f_presser_update_trigger BEFORE UPDATE ON press_f_presser FOR EACH ROW EXECUTE PROCEDURE update_trigger_procedure(); + + + DROP TRIGGER IF EXISTS press_f_presser_insert_trigger ON press_f_presser; + CREATE TRIGGER press_f_presser_insert_trigger BEFORE INSERT ON press_f_presser FOR EACH ROW EXECUTE PROCEDURE insert_trigger_procedure(); + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/tables/tables.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/tables/tables.xml new file mode 100644 index 000000000..8b06b0f71 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/1.5.14/tables/tables.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/entertainment-changeLog.xml b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/entertainment-changeLog.xml index fd50c0ff5..d8688eaff 100644 --- a/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/entertainment-changeLog.xml +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-impl/src/main/resources/migrations/entertainment-changeLog.xml @@ -13,4 +13,5 @@ + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/config/EntertainmentFeatureConfig.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/config/EntertainmentFeatureConfig.java index d201f2f10..60dd2450e 100644 --- a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/config/EntertainmentFeatureConfig.java +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/config/EntertainmentFeatureConfig.java @@ -12,6 +12,7 @@ public class EntertainmentFeatureConfig implements FeatureConfig { public static final String ROULETTE_BULLETS_CONFIG_KEY = "rouletteBullets"; public static final String ROLL_DEFAULT_HIGH_KEY = "rollDefaultHigh"; + public static final String PRESS_F_DEFAULT_DURATION_SECONDS = "pressFDefaultDurationSeconds"; @Override public FeatureDefinition getFeature() { return EntertainmentFeatureDefinition.ENTERTAINMENT; @@ -19,6 +20,6 @@ public class EntertainmentFeatureConfig implements FeatureConfig { @Override public List getRequiredSystemConfigKeys() { - return Arrays.asList(ROULETTE_BULLETS_CONFIG_KEY, ROLL_DEFAULT_HIGH_KEY); + return Arrays.asList(ROULETTE_BULLETS_CONFIG_KEY, ROLL_DEFAULT_HIGH_KEY, PRESS_F_DEFAULT_DURATION_SECONDS); } } diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/exception/AlreadyPressedFException.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/exception/AlreadyPressedFException.java new file mode 100644 index 000000000..0ddc1a749 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/exception/AlreadyPressedFException.java @@ -0,0 +1,15 @@ +package dev.sheldan.abstracto.entertainment.exception; + +import dev.sheldan.abstracto.core.exception.AbstractoTemplatableException; + +public class AlreadyPressedFException extends AbstractoTemplatableException { + @Override + public String getTemplateName() { + return "already_pressed_f_exception"; + } + + @Override + public Object getTemplateModel() { + return new Object(); + } +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/command/PressFJoinModel.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/command/PressFJoinModel.java new file mode 100644 index 000000000..41233fb7f --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/command/PressFJoinModel.java @@ -0,0 +1,14 @@ +package dev.sheldan.abstracto.entertainment.model.command; + +import dev.sheldan.abstracto.core.models.template.display.MemberDisplay; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Builder +@Setter +@Getter +public class PressFJoinModel { + private MemberDisplay memberDisplay; + private Long messageId; +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/command/PressFPromptModel.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/command/PressFPromptModel.java new file mode 100644 index 000000000..14c81fda2 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/command/PressFPromptModel.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.entertainment.model.command; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Builder +@Setter +@Getter +public class PressFPromptModel { + private String text; + private String pressFComponentId; +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/command/PressFResultModel.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/command/PressFResultModel.java new file mode 100644 index 000000000..1dcd10785 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/command/PressFResultModel.java @@ -0,0 +1,14 @@ +package dev.sheldan.abstracto.entertainment.model.command; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Builder +@Setter +@Getter +public class PressFResultModel { + private Long userCount; + private String text; + private Long messageId; +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/database/PressF.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/database/PressF.java new file mode 100644 index 000000000..9e35e1351 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/database/PressF.java @@ -0,0 +1,62 @@ +package dev.sheldan.abstracto.entertainment.model.database; + +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AServer; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import jakarta.persistence.*; +import lombok.*; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +@Builder +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "press_f") +@Getter +@Setter +@EqualsAndHashCode +public class PressF { + @Id + @Column(name = "id", nullable = false) + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "creator_user_id", nullable = false) + private AUserInAServer creator; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "server_id", nullable = false) + private AServer server; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "press_f_channel_id", nullable = false) + private AChannel pressFChannel; + + @Column(name = "message_id", nullable = false) + private Long messageId; + + @Column(name = "text") + private String text; + + @Column(name = "target_date", nullable = false) + private Instant targetDate; + + @Column(name = "created", nullable = false, insertable = false, updatable = false) + private Instant created; + + @Column(name = "updated", insertable = false, updatable = false) + private Instant updated; + + @OneToMany( + fetch = FetchType.LAZY, + orphanRemoval = true, + cascade = {CascadeType.PERSIST, CascadeType.MERGE}, + mappedBy = "pressF") + @Builder.Default + private List presser = new ArrayList<>(); + +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/database/PressFPresser.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/database/PressFPresser.java new file mode 100644 index 000000000..bbc9bbcaf --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/database/PressFPresser.java @@ -0,0 +1,38 @@ +package dev.sheldan.abstracto.entertainment.model.database; + +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.entertainment.model.database.embed.PressFPresserId; +import jakarta.persistence.*; +import lombok.*; + +import java.time.Instant; + +@Builder +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "press_f_presser") +@Getter +@Setter +@EqualsAndHashCode +public class PressFPresser { + + @EmbeddedId + @Getter + private PressFPresserId id; + + @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.LAZY) + @MapsId("presserId") + @JoinColumn(name = "press_f_presser_user_in_server_id", nullable = false) + private AUserInAServer presser; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(updatable = false, insertable = false, name = "press_f_id", referencedColumnName = "id") + private PressF pressF; + + @Column(name = "created", nullable = false, insertable = false, updatable = false) + private Instant created; + + @Column(name = "updated", insertable = false, updatable = false) + private Instant updated; +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/database/embed/PressFPresserId.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/database/embed/PressFPresserId.java new file mode 100644 index 000000000..e3fc061ea --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/model/database/embed/PressFPresserId.java @@ -0,0 +1,27 @@ +package dev.sheldan.abstracto.entertainment.model.database.embed; + +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import lombok.*; + +import java.io.Serializable; + +@Embeddable +@Getter +@Setter +@Builder +@EqualsAndHashCode +@NoArgsConstructor +@AllArgsConstructor +public class PressFPresserId implements Serializable { + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "press_f_presser_user_in_server_id") + private Long presserId; + + @Column(name = "press_f_id") + private Long pressFId; + + +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/EntertainmentService.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/EntertainmentService.java index b3983fe19..b0182760d 100644 --- a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/EntertainmentService.java +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/EntertainmentService.java @@ -1,9 +1,13 @@ package dev.sheldan.abstracto.entertainment.service; import dev.sheldan.abstracto.entertainment.exception.ReactDuplicateCharacterException; +import dev.sheldan.abstracto.entertainment.model.command.PressFPromptModel; import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; +import java.time.Duration; import java.util.List; +import java.util.concurrent.CompletableFuture; public interface EntertainmentService { String getEightBallValue(String text); @@ -12,6 +16,10 @@ public interface EntertainmentService { boolean executeRoulette(Member memberExecuting); String takeChoice(List choices, Member memberExecuting); String createMockText(String text, Member memberExecuting, Member mockedUser); + PressFPromptModel getPressFModel(String text); + void persistPressF(String text, Duration duration, Member executingMember, String componentId, GuildMessageChannel guildMessageChannel, Long messageId); + + CompletableFuture evaluatePressF(Long pressFId); /** * Converts the given text to unicode characters (with predefined values from a manual mapping) and returns the matched diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFManagementService.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFManagementService.java new file mode 100644 index 000000000..1058216a0 --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFManagementService.java @@ -0,0 +1,13 @@ +package dev.sheldan.abstracto.entertainment.service.management; + +import dev.sheldan.abstracto.core.models.database.AChannel; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.entertainment.model.database.PressF; + +import java.time.Instant; +import java.util.Optional; + +public interface PressFManagementService { + PressF createPressF(String text, Instant targetDate, AUserInAServer creator, AChannel channel, Long messageId); + Optional getPressFById(Long pressFId); +} diff --git a/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFPresserManagementService.java b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFPresserManagementService.java new file mode 100644 index 000000000..5d97ee5dd --- /dev/null +++ b/abstracto-application/abstracto-modules/entertainment/entertainment-int/src/main/java/dev/sheldan/abstracto/entertainment/service/management/PressFPresserManagementService.java @@ -0,0 +1,10 @@ +package dev.sheldan.abstracto.entertainment.service.management; + +import dev.sheldan.abstracto.core.models.database.AUserInAServer; +import dev.sheldan.abstracto.entertainment.model.database.PressF; +import dev.sheldan.abstracto.entertainment.model.database.PressFPresser; + +public interface PressFPresserManagementService { + PressFPresser addPresser(PressF pressF, AUserInAServer presser); + boolean didUserAlreadyPress(PressF pressF, AUserInAServer aUserInAServer); +} diff --git a/abstracto-application/abstracto-modules/giveaway/giveaway-impl/src/main/java/dev/sheldan/abstracto/giveaway/service/GiveawayServiceBean.java b/abstracto-application/abstracto-modules/giveaway/giveaway-impl/src/main/java/dev/sheldan/abstracto/giveaway/service/GiveawayServiceBean.java index 6f3f4701d..e586456a3 100644 --- a/abstracto-application/abstracto-modules/giveaway/giveaway-impl/src/main/java/dev/sheldan/abstracto/giveaway/service/GiveawayServiceBean.java +++ b/abstracto-application/abstracto-modules/giveaway/giveaway-impl/src/main/java/dev/sheldan/abstracto/giveaway/service/GiveawayServiceBean.java @@ -148,6 +148,7 @@ public class GiveawayServiceBean implements GiveawayService { Giveaway giveaway = giveAwayOptional.get(); Set winners = new HashSet<>(); Integer winnerCount = giveaway.getWinnerCount(); + giveaway.getParticipants().forEach(giveawayParticipant -> giveawayParticipant.setWon(false)); List potentialWinners = new ArrayList<>(giveaway .getParticipants() .stream() @@ -170,6 +171,7 @@ public class GiveawayServiceBean implements GiveawayService { .stream() .filter(giveawayParticipant -> winners.contains(giveawayParticipant.getParticipant().getUserInServerId())) .toList(); + winningParticipants.forEach(giveawayParticipant -> giveawayParticipant.setWon(true)); List winnerDisplays = winningParticipants .stream() .map(giveawayParticipant -> MemberDisplay.fromAUserInAServer(giveawayParticipant.getParticipant())) diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandManager.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandManager.java index 8b99c2cd0..cc4fa4fca 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandManager.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandManager.java @@ -126,7 +126,8 @@ public class CommandManager implements CommandRegistry { } return commandConfiguration .getParameters() - .stream().filter(parameter -> isParameterRequired(parameter, serverId)) + .stream().filter(parameter -> !parameter.getSlashCommandOnly()) + .filter(parameter -> isParameterRequired(parameter, serverId)) .count(); }