142 lines
4.8 KiB
Java

package ru.emotilt.antiplatka.poll;
import java.time.Duration;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.jetbrains.annotations.Nullable;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.api.utils.messages.MessagePollBuilder;
import net.dv8tion.jda.api.utils.messages.MessagePollData;
import ru.emotilt.antiplatka.Bot;
public abstract class BotPoll {
public final @Nullable Message message;
// TODO: Create an abstraction for targets. This means that it can have any
// targets except the user.
public final Member targetUser;
public final @Nullable MessageChannel channel;
public final Date start;
public final Duration voteDuration;
public abstract void endVote();
public abstract String getEndAnnouncementText(boolean success);
@SuppressWarnings("method.invocation")
public BotPoll(@Nullable Message message, Member targetUser, @Nullable MessageChannel channel, Date start, Duration voteDuration) {
this.message = message;
this.targetUser = targetUser;
this.channel = channel;
this.start = start;
this.voteDuration = voteDuration;
schedule(message);
}
/**
* Queue to complete the poll.
* This is required if the poll lasts less than 1 hour.
*
* @param message A message containing a poll.
*/
public void schedule(@Nullable Message message) {
if (isShort()) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(() -> {
try {
Thread.sleep(voteDuration.toMillis());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Objects.requireNonNull(message).endPoll().queue();
});
executorService.shutdown();
}
}
protected boolean isShort() {
// The Discord API does not allow polls that are less than 1 hour in length.
return voteDuration.toMillis() < TimeUnit.HOURS.toMillis(1);
}
@SuppressWarnings("unused")
public static abstract class Builder<T extends Builder<T>> {
protected @Nullable Message message = null;
protected Member targetUser;
protected @Nullable MessageChannel channel = null;
protected Date start = new Date();
protected Duration voteDuration;
protected abstract T self();
public Builder(Member targetUser, Duration voteDuration) {
this.targetUser = targetUser;
this.voteDuration = voteDuration;
}
public T message(Message message) {
this.message = message;
return self();
}
public T targetUser(Member targetUser) {
this.targetUser = targetUser;
return self();
}
public T channel(MessageChannel channel) {
this.channel = channel;
return self();
}
public T start(Date start) {
this.start = start;
return self();
}
public T voteDuration(Duration voteDuration) {
this.voteDuration = voteDuration;
return self();
}
public MessageCreateBuilder buildMessage(String announcementText) {
String title = announcementText + ". Порог голосования **%d%%**.";
title = String.format(title, Bot.config.threshold);
MessagePollData poll = new MessagePollBuilder("Голосование")
.addAnswer("Да", Emoji.fromUnicode(""))
.addAnswer("Нет", Emoji.fromUnicode(""))
.setDuration(
isShort() ? TimeUnit.HOURS.toMinutes(1)
: voteDuration.toMinutes(),
TimeUnit.MINUTES)
.build();
if (isShort()) {
title += String.format(" Голосование закончится <t:%d:R>",
start.getTime() / 1000 + voteDuration.toSeconds());
}
return new MessageCreateBuilder().addContent(title).setPoll(poll);
}
protected boolean isShort() {
// The Discord API does not allow polls that are less than 1 hour in length.
return voteDuration.toMillis() < TimeUnit.HOURS.toMillis(1);
}
// Abstract build method to be implemented by subclasses
public abstract BotPoll build();
}
}