diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/command/ShowPoll.java b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/command/ShowPoll.java new file mode 100644 index 000000000..5792667f8 --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/command/ShowPoll.java @@ -0,0 +1,95 @@ +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.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.suggestion.config.SuggestionFeatureDefinition; +import dev.sheldan.abstracto.suggestion.config.SuggestionSlashCommandNames; +import dev.sheldan.abstracto.suggestion.model.template.PollInfoModel; +import dev.sheldan.abstracto.suggestion.service.PollService; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +public class ShowPoll extends AbstractConditionableCommand { + + private static final String COMMAND_NAME = "show"; + private static final String SHOW_POLL_COMMAND_NAME = "showPoll"; + private static final String POLL_ID_PARAMETER = "pollId"; + private static final String SHOW_POLL_TEMPLATE_KEY = "showPoll_response"; + + @Autowired + private SlashCommandParameterService slashCommandParameterService; + + @Autowired + private PollService pollService; + + @Autowired + private InteractionService interactionService; + + @Override + public CompletableFuture executeSlash(SlashCommandInteractionEvent event) { + Long suggestionId = slashCommandParameterService.getCommandOption(POLL_ID_PARAMETER, event, Long.class, Integer.class).longValue(); + PollInfoModel pollInfoModel = pollService.getPollInfoModel(suggestionId, event.getGuild().getIdLong()); + return interactionService.replyEmbed(SHOW_POLL_TEMPLATE_KEY, pollInfoModel, event) + .thenApply(interactionHook -> CommandResult.fromSuccess()); + } + + @Override + public CommandConfiguration getConfiguration() { + List polldIdValidator = Arrays.asList(MinIntegerValueValidator.min(1L)); + Parameter pollIdParameter = Parameter + .builder() + .name(POLL_ID_PARAMETER) + .validators(polldIdValidator) + .type(Long.class) + .templated(true) + .build(); + + HelpInfo helpInfo = HelpInfo + .builder() + .templated(true) + .hasExample(false) + .build(); + + List parameters = Arrays.asList(pollIdParameter); + + SlashCommandConfig slashCommandConfig = SlashCommandConfig + .builder() + .enabled(true) + .rootCommandName(SuggestionSlashCommandNames.POLL) + .commandName(COMMAND_NAME) + .build(); + + return CommandConfiguration.builder() + .name(SHOW_POLL_COMMAND_NAME) + .slashCommandConfig(slashCommandConfig) + .module(UtilityModuleDefinition.UTILITY) + .templated(true) + .async(true) + .supportsEmbedException(true) + .causesReaction(false) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureDefinition getFeature() { + return SuggestionFeatureDefinition.POLL; + } +} diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/PollServiceBean.java b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/PollServiceBean.java index a5a9037d8..fcc39bcbd 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/PollServiceBean.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/PollServiceBean.java @@ -335,7 +335,8 @@ public class PollServiceBean implements PollService { public CompletableFuture addOptionToServerPoll(Long pollId, Long serverId, Member adder, String label, String description) { Poll poll = pollManagementService.getPollByPollId(pollId, serverId, PollType.STANDARD); log.info("Adding option to server poll {} in server {}.", pollId, serverId); - pollOptionManagementService.addOptionToPoll(poll, label, description); + AUserInAServer adderUser = userInServerManagementService.loadOrCreateUser(adder); + pollOptionManagementService.addOptionToPoll(poll, label, description, adderUser); List options = getOptionsOfPoll(poll); ServerPollMessageModel model = ServerPollMessageModel.fromPoll(poll, options); MessageToSend messageToSend = templateService.renderEmbedTemplate(SERVER_POLL_TEMPLATE_KEY, model); @@ -487,6 +488,37 @@ public class PollServiceBean implements PollService { return messageService.deleteMessageInChannelInServer(serverId, poll.getChannel().getId(), poll.getMessageId()); } + @Override + public PollInfoModel getPollInfoModel(Long pollId, Long serverId) { + Poll poll = pollManagementService.getPollByPollId(pollId, serverId, PollType.STANDARD); + Integer totalVotes = getTotalVotesOfPoll(poll); + List optionInfoModels = poll.getOptions().stream().map(pollOption -> { + Long voteCount = getVotesOfOption(poll, pollOption); + return PollOptionInfoModel + .builder() + .value(pollOption.getValue()) + .description(pollOption.getDescription()) + .label(pollOption.getLabel()) + .votes(voteCount) + .percentage(totalVotes > 0 ? (voteCount / (float) totalVotes) * 100 : 0) + .adder(pollOption.getAdder() != null ? MemberDisplay.fromAUserInAServer(pollOption.getAdder()) : null) + .build(); + }).toList(); + return PollInfoModel + .builder() + .id(poll.getPollId()) + .description(poll.getDescription()) + .creationDate(poll.getCreated()) + .targetDate(poll.getTargetDate()) + .totalVotes(totalVotes) + .allowAdditions(poll.getAllowAddition()) + .allowMultiple(poll.getAllowMultiple()) + .options(optionInfoModels) + .showDecisions(poll.getShowDecisions()) + .pollDuration(Duration.between(poll.getCreated(), poll.getTargetDate())) + .build(); + } + @Transactional public CompletableFuture updateFinalPollMessage(Long pollId, Guild guild) { Poll poll = pollManagementService.getPollByPollId(pollId, guild.getIdLong(), PollType.STANDARD); @@ -543,22 +575,13 @@ public class PollServiceBean implements PollService { .percentage(0f) .description(description) .build(); - }).collect(Collectors.toList()); + }).toList(); } private List getOptionsOfPoll(Poll poll) { - Integer totalVotes = poll - .getDecisions() - .stream() - .map(userDecision -> userDecision.getOptions().size()) - .mapToInt(Integer::intValue) - .sum(); + Integer totalVotes = getTotalVotesOfPoll(poll); return poll.getOptions().stream().map(option -> { - Long voteCount = poll - .getDecisions() - .stream() - .filter(decision -> decision.getOptions().stream().anyMatch(pollUserDecisionOption -> pollUserDecisionOption.getPollOption().equals(option))) - .count(); + Long voteCount = getVotesOfOption(poll, option); return PollMessageOption .builder() .value(option.getValue()) @@ -567,7 +590,24 @@ public class PollServiceBean implements PollService { .percentage(totalVotes > 0 ? (voteCount / (float) totalVotes) * 100 : 0) .description(option.getDescription()) .build(); - }).collect(Collectors.toList()); + }).toList(); + } + + private Long getVotesOfOption(Poll poll, PollOption option) { + return poll + .getDecisions() + .stream() + .filter(decision -> decision.getOptions().stream().anyMatch(pollUserDecisionOption -> pollUserDecisionOption.getPollOption().equals(option))) + .count(); + } + + private Integer getTotalVotesOfPoll(Poll poll) { + return poll + .getDecisions() + .stream() + .map(userDecision -> userDecision.getOptions().size()) + .mapToInt(Integer::intValue) + .sum(); } } diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/management/PollOptionManagementServiceBean.java b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/management/PollOptionManagementServiceBean.java index a3c9335ed..b81f88d9e 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/management/PollOptionManagementServiceBean.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/java/dev/sheldan/abstracto/suggestion/service/management/PollOptionManagementServiceBean.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.suggestion.service.management; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.suggestion.model.PollCreationRequest; import dev.sheldan.abstracto.suggestion.model.database.Poll; import dev.sheldan.abstracto.suggestion.model.database.PollOption; @@ -32,12 +33,18 @@ public class PollOptionManagementServiceBean implements PollOptionManagementServ @Override public void addOptionToPoll(Poll poll, String label, String description) { + addOptionToPoll(poll, label, description, null); + } + + @Override + public void addOptionToPoll(Poll poll, String label, String description, AUserInAServer adder) { PollOption option = PollOption .builder() .poll(poll) .label(label) .value(label) .server(poll.getServer()) + .adder(adder) .description(description) .build(); pollOptionRepository.save(option); diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.5.6/collection.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.5.6/collection.xml new file mode 100644 index 000000000..121b5aadf --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.5.6/collection.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.5.6/seedData/command.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.5.6/seedData/command.xml new file mode 100644 index 000000000..43117f623 --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.5.6/seedData/command.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.5.6/seedData/data.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.5.6/seedData/data.xml new file mode 100644 index 000000000..c048f6f53 --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/1.5.6/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/suggestion-changeLog.xml b/abstracto-application/abstracto-modules/suggestion/suggestion-impl/src/main/resources/migrations/suggestion-changeLog.xml index 56737ba6b..735f16a22 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 @@ -13,4 +13,5 @@ + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/PollInfoModel.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/PollInfoModel.java new file mode 100644 index 000000000..6d3e8b20d --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/PollInfoModel.java @@ -0,0 +1,25 @@ +package dev.sheldan.abstracto.suggestion.model.template; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; + +@Getter +@Setter +@Builder +public class PollInfoModel { + private Long id; + private String description; + private Boolean allowMultiple; + private Boolean showDecisions; + private Boolean allowAdditions; + private Instant creationDate; + private Integer totalVotes; + private Instant targetDate; + private Duration pollDuration; + private List options; +} diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/PollOptionInfoModel.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/PollOptionInfoModel.java new file mode 100644 index 000000000..20d39a0cb --- /dev/null +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/model/template/PollOptionInfoModel.java @@ -0,0 +1,18 @@ +package dev.sheldan.abstracto.suggestion.model.template; + +import dev.sheldan.abstracto.core.models.template.display.MemberDisplay; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class PollOptionInfoModel { + private String value; + private String label; + private String description; + private Long votes; + private Float percentage; + private MemberDisplay adder; +} diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/PollService.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/PollService.java index 26eadebde..4684ff319 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/PollService.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/PollService.java @@ -1,6 +1,7 @@ package dev.sheldan.abstracto.suggestion.service; import dev.sheldan.abstracto.suggestion.model.database.PollType; +import dev.sheldan.abstracto.suggestion.model.template.PollInfoModel; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.interactions.InteractionHook; @@ -26,4 +27,5 @@ public interface PollService { CompletableFuture evaluateQuickPoll(Long pollId, Long serverId); CompletableFuture closePoll(Long pollId, Long serverId, String text, Member cause); CompletableFuture cancelPoll(Long pollId, Long serverId, Member cause); + PollInfoModel getPollInfoModel(Long pollId, Long serverId); } diff --git a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/management/PollOptionManagementService.java b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/management/PollOptionManagementService.java index 6c806d5a1..6f7a0c041 100644 --- a/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/management/PollOptionManagementService.java +++ b/abstracto-application/abstracto-modules/suggestion/suggestion-int/src/main/java/dev/sheldan/abstracto/suggestion/service/management/PollOptionManagementService.java @@ -1,5 +1,6 @@ package dev.sheldan.abstracto.suggestion.service.management; +import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.suggestion.model.PollCreationRequest; import dev.sheldan.abstracto.suggestion.model.database.Poll; import dev.sheldan.abstracto.suggestion.model.database.PollOption; @@ -9,5 +10,6 @@ import java.util.Optional; public interface PollOptionManagementService { void addOptionsToPoll(Poll poll, PollCreationRequest pollCreationRequest); void addOptionToPoll(Poll poll, String label, String description); + void addOptionToPoll(Poll poll, String label, String description, AUserInAServer adder); Optional getPollOptionByName(Poll poll, String key); }