diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/Commands.java b/application/src/main/java/org/togetherjava/tjbot/commands/Commands.java index 556ea519d2..43e0a8b3cc 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/Commands.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/Commands.java @@ -8,6 +8,7 @@ import org.togetherjava.tjbot.commands.mathcommands.TeXCommand; import org.togetherjava.tjbot.commands.moderation.*; import org.togetherjava.tjbot.commands.moderation.temp.TemporaryModerationRoutine; +import org.togetherjava.tjbot.commands.reminder.ReminderCommand; import org.togetherjava.tjbot.commands.tags.TagCommand; import org.togetherjava.tjbot.commands.tags.TagManageCommand; import org.togetherjava.tjbot.commands.tags.TagSystem; @@ -72,6 +73,7 @@ public enum Commands { commands.add(new AuditCommand(actionsStore)); commands.add(new MuteCommand(actionsStore)); commands.add(new UnmuteCommand(actionsStore)); + commands.add(new ReminderCommand()); return commands; } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/reminder/ReminderCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/reminder/ReminderCommand.java new file mode 100644 index 0000000000..d3cec6ef63 --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/reminder/ReminderCommand.java @@ -0,0 +1,151 @@ +package org.togetherjava.tjbot.commands.reminder; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.events.interaction.SlashCommandEvent; +import net.dv8tion.jda.api.interactions.commands.OptionMapping; +import net.dv8tion.jda.api.interactions.commands.OptionType; +import net.dv8tion.jda.api.requests.restaction.interactions.ReplyAction; +import org.jetbrains.annotations.NotNull; +import org.togetherjava.tjbot.commands.SlashCommandAdapter; +import org.togetherjava.tjbot.commands.SlashCommandVisibility; + +import java.awt.*; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** + * This creates a command called {@code /remind}, which reminds the user about a certain activity or + * event + * + *

+ * For example: + * + *

+ * {@code
+ * /remind from: 26.09.2021 to: 03.10.2021 @User Message
+ * /remind 10 seconds @User User Message
+ * }
+ * 
+ */ + +public class ReminderCommand extends SlashCommandAdapter { + + static final Color AMBIENT_COLOR = Color.decode("#FA8072"); + private static final String REMINDER = "reminder"; + private static final String OPTIONAL_USER_MENTION = "remind-who"; + private static final String OPTIONAL_USER_MESSAGE = "user-message"; + + /* + * Creates an Instance of the command. + */ + public ReminderCommand() { + super("reminder", "Reminds user about certain activity or event", + SlashCommandVisibility.GUILD); + getData() + .addOption(OptionType.STRING, REMINDER, + "Reminds the user about certain activity or an event", true) + .addOption(OptionType.USER, OPTIONAL_USER_MENTION, "Optionally the user to be reminded", + false) + .addOption(OptionType.STRING, OPTIONAL_USER_MESSAGE, "Optionally to write a message", + false); + } + + @Override + public void onSlashCommand(@NotNull SlashCommandEvent event) { + String reminder = Objects.requireNonNull(event.getOption(REMINDER)).getAsString(); + OptionMapping userMention = event.getOption(OPTIONAL_USER_MENTION); + OptionMapping userMessage = event.getOption(OPTIONAL_USER_MESSAGE); + + String[] data = reminder.split(" ", 2); + // TODO Make it so that it can support multiple units like: 1 minute 20 seconds, 2 hour 20 + // minutes, 2 days 20 hours + int duration = Integer.parseInt(data[0]); + ChronoUnit unit = switch (data[1]) { + case "second", "seconds" -> ChronoUnit.SECONDS; + case "minute", "minutes" -> ChronoUnit.MINUTES; + case "hour", "hours" -> ChronoUnit.HOURS; + case "day", "days" -> ChronoUnit.DAYS; + default -> throw new IllegalArgumentException( + "Unsupported duration: " + reminder + " use Numbers only (EN)"); + }; + ReplyAction option; + if (userMessage != null && userMention != null) { + option = setMentionAndMessageReply(event, reminder, userMention, userMessage, duration, + unit); + } else if (userMention != null) { + option = setUserMentionReply(event, reminder, userMention, duration, unit); + } else if (userMessage != null) { + option = setUserMessageReply(event, reminder, userMessage, duration, unit); + } else { + option = event.replyEmbeds(new EmbedBuilder().setTitle("Reminder") + .setDescription("You will be reminded in " + reminder) + .setFooter(event.getUser().getName() + " • used " + event.getCommandString()) + .setTimestamp(Instant.now()) + .setColor(AMBIENT_COLOR) + .build()); + event.getChannel() + .sendMessage(event.getUser().getAsMention() + " pinging you just to remind you.") + .queueAfter(duration, TimeUnit.of(unit)); + } + option.queue(); + } + + @NotNull + private ReplyAction setMentionAndMessageReply(@NotNull SlashCommandEvent event, String reminder, + OptionMapping userMention, OptionMapping userMessage, int duration, ChronoUnit unit) { + ReplyAction option; + option = event + .replyEmbeds(new EmbedBuilder().setTitle("Reminder") + .setDescription("User " + userMention.getAsUser().getAsMention() + + " will be reminded in " + reminder + " with the message **" + + userMessage.getAsString() + "**") + .setFooter(event.getUser().getName() + " • used " + event.getCommandString()) + .setTimestamp(Instant.now()) + .setColor(AMBIENT_COLOR) + .build()); + event.getChannel() + .sendMessage("Reminder for " + userMention.getAsUser().getAsMention() + " about **" + + userMessage.getAsString() + "**.") + .queueAfter(duration, TimeUnit.of(unit)); + return option; + } + + @NotNull + private ReplyAction setUserMentionReply(@NotNull SlashCommandEvent event, String reminder, + OptionMapping userMention, int duration, ChronoUnit unit) { + ReplyAction option; + option = event.replyEmbeds(new EmbedBuilder().setTitle("Reminder") + .setDescription("User " + userMention.getAsUser().getAsMention() + + " will be reminded in " + reminder) + .setFooter(event.getUser().getName() + " • used " + event.getCommandString()) + .setTimestamp(Instant.now()) + .setColor(AMBIENT_COLOR) + .build()); + + event.getChannel() + .sendMessage( + userMention.getAsUser().getAsMention() + " pinging you just to remind you.") + .queueAfter(duration, TimeUnit.of(unit)); + return option; + } + + @NotNull + private ReplyAction setUserMessageReply(@NotNull SlashCommandEvent event, String reminder, + OptionMapping userMessage, int duration, ChronoUnit unit) { + ReplyAction option; + option = event.replyEmbeds(new EmbedBuilder().setTitle("Reminder") + .setDescription( + reminder + " reminder with the message **" + userMessage.getAsString() + "**") + .setFooter(event.getUser().getName() + " • used " + event.getCommandString()) + .setTimestamp(Instant.now()) + .setColor(AMBIENT_COLOR) + .build()); + event.getChannel() + .sendMessage(event.getUser().getAsMention() + " reminder with the message **" + + userMessage.getAsString() + "**") + .queueAfter(duration, TimeUnit.of(unit)); + return option; + } +} diff --git a/application/src/main/resources/db/V7_ADD_REMINDER_TIME.sql b/application/src/main/resources/db/V7_ADD_REMINDER_TIME.sql new file mode 100644 index 0000000000..7529ef233d --- /dev/null +++ b/application/src/main/resources/db/V7_ADD_REMINDER_TIME.sql @@ -0,0 +1,10 @@ +CREATE TABLE reminder_actions +( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + issued_at TIMESTAMP NOT NULL, + author_id BIGINT NOT NULL, + expires_at TIMESTAMP NOT NULL, + expired INT NOT NULL, + optional_message VARCHAR(100), + optional_mention VARCHAR(25) +) \ No newline at end of file