[AB-94] adding command to show the state of a server poll

This commit is contained in:
Sheldan
2023-09-03 00:19:35 +02:00
parent f3144eb094
commit f03bee8b1e
11 changed files with 244 additions and 14 deletions

View File

@@ -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<CommandResult> 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<ParameterValidator> 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<Parameter> 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;
}
}

View File

@@ -335,7 +335,8 @@ public class PollServiceBean implements PollService {
public CompletableFuture<Void> 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<PollMessageOption> 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<PollOptionInfoModel> 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<Void> 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<PollMessageOption> 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();
}
}

View File

@@ -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);

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="seedData/data.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -0,0 +1,20 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<property name="utilityModule" value="(SELECT id FROM module WHERE name = 'utility')"/>
<property name="pollFeature" value="(SELECT id FROM feature WHERE key = 'poll')"/>
<changeSet author="Sheldan" id="showPoll-command">
<insert tableName="command">
<column name="name" value="showPoll"/>
<column name="module_id" valueComputed="${utilityModule}"/>
<column name="feature_id" valueComputed="${pollFeature}"/>
</insert>
</changeSet>
</databaseChangeLog>

View File

@@ -0,0 +1,10 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
xmlns:pro="http://www.liquibase.org/xml/ns/pro"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog dbchangelog.xsd
http://www.liquibase.org/xml/ns/dbchangelog-ext dbchangelog.xsd
http://www.liquibase.org/xml/ns/pro dbchangelog.xsd" >
<include file="command.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -13,4 +13,5 @@
<include file="1.4.0/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.8/collection.xml" relativeToChangelogFile="true"/>
<include file="1.4.26/collection.xml" relativeToChangelogFile="true"/>
<include file="1.5.6/collection.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

View File

@@ -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<PollOptionInfoModel> options;
}

View File

@@ -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;
}

View File

@@ -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<Void> evaluateQuickPoll(Long pollId, Long serverId);
CompletableFuture<Void> closePoll(Long pollId, Long serverId, String text, Member cause);
CompletableFuture<Void> cancelPoll(Long pollId, Long serverId, Member cause);
PollInfoModel getPollInfoModel(Long pollId, Long serverId);
}

View File

@@ -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<PollOption> getPollOptionByName(Poll poll, String key);
}