diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/basic/VcActivityCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/basic/VcActivityCommand.java
index 0f56fb4fbd..09e008e39c 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/basic/VcActivityCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/basic/VcActivityCommand.java
@@ -19,11 +19,12 @@
import org.slf4j.LoggerFactory;
import org.togetherjava.tjbot.commands.SlashCommandAdapter;
import org.togetherjava.tjbot.commands.SlashCommandVisibility;
-
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
/**
* Implements the {@code vc-activity} command. Creates VC activities.
@@ -45,6 +46,9 @@ public final class VcActivityCommand extends SlashCommandAdapter {
private static final String MAX_USES_OPTION = "max-uses";
private static final String MAX_AGE_OPTION = "max-age";
+ private static final long MAX_AGE_DAYS_LIMIT = 7;
+ private static final long MAX_USES_LIMIT = 100;
+
public static final String YOUTUBE_TOGETHER_NAME = "YouTube Together";
public static final String POKER_NAME = "Poker";
public static final String BETRAYAL_IO_NAME = "Betrayal.io";
@@ -69,7 +73,6 @@ public final class VcActivityCommand extends SlashCommandAdapter {
new Command.Choice(WORDSNACK_NAME, WORDSNACK_NAME),
new Command.Choice(LETTERTILE_NAME, LETTERTILE_NAME));
-
/**
* List comes from the "Implement
* invite targets" PR on JDA. There is no official list from Discord themselves, so this is
@@ -82,12 +85,15 @@ public final class VcActivityCommand extends SlashCommandAdapter {
"852509694341283871", DOODLECREW_NAME, "878067389634314250", WORDSNACK_NAME,
"879863976006127627", LETTERTILE_NAME, "879863686565621790");
- private static final List inviteOptions = List.of(
- new OptionData(OptionType.STRING, MAX_USES_OPTION,
- "The amount of times the invite can be used, default is infinity", false),
+ private static final List inviteOptions = List.of(new OptionData(OptionType.INTEGER,
+ MAX_USES_OPTION,
+ "How many times this invite can be used, 0 infinite (default) - %d being the highest."
+ .formatted(MAX_USES_LIMIT),
+ false).setRequiredRange(0, MAX_USES_LIMIT),
new OptionData(OptionType.INTEGER, MAX_AGE_OPTION,
- "Max age in seconds. Set this to 0 to never expire, default is 1 day", false));
-
+ "How long, in days this activity can be used before it expires, 0 (No expiry), Max is %d days."
+ .formatted(MAX_AGE_DAYS_LIMIT),
+ false).setRequiredRange(0, MAX_AGE_DAYS_LIMIT));
/**
* Constructs an instance
@@ -148,29 +154,10 @@ public void onSlashCommand(@NotNull SlashCommandEvent event) {
OptionMapping maxUsesOption = event.getOption(MAX_USES_OPTION);
OptionMapping maxAgeOption = event.getOption(MAX_AGE_OPTION);
- Integer maxUses;
-
- // the user already received the error in the handleIntegerTypeOption method
- // it still throws to tell us to return this method and stop the proceeding code
- try {
- maxUses = handleIntegerTypeOption(event, maxUsesOption);
- } catch (IllegalArgumentException ignore) {
- return;
- }
-
- Integer maxAge;
-
- // the user already received the error in the handleIntegerTypeOption method
- // it still throws to tell us to return this method and stop the proceeding code
- try {
- maxAge = handleIntegerTypeOption(event, maxAgeOption);
- } catch (IllegalArgumentException ignore) {
- return;
- }
-
-
String applicationId;
String applicationName;
+ Integer maxUses = requireIntOptionIfPresent(maxUsesOption);
+ Integer maxAgeDays = requireIntOptionIfPresent(maxAgeOption);
if (applicationOption != null) {
applicationName = applicationOption.getAsString();
@@ -182,9 +169,10 @@ public void onSlashCommand(@NotNull SlashCommandEvent event) {
getKeyByValue(VC_APPLICATION_TO_ID, applicationId).orElse("an activity");
}
- handleSubcommand(event, voiceChannel, applicationId, maxUses, maxAge, applicationName);
+ handleSubcommand(event, voiceChannel, applicationId, maxUses, maxAgeDays, applicationName);
}
+
private static @NotNull Optional getKeyByValue(@NotNull Map map,
@NotNull V value) {
for (Map.Entry entry : map.entrySet()) {
@@ -198,14 +186,18 @@ public void onSlashCommand(@NotNull SlashCommandEvent event) {
private static void handleSubcommand(@NotNull SlashCommandEvent event,
@NotNull VoiceChannel voiceChannel, @NotNull String applicationId,
- @Nullable Integer maxUses, @Nullable Integer maxAge, @NotNull String applicationName) {
+ @Nullable Integer maxUses, @Nullable Integer maxAgeDays,
+ @NotNull String applicationName) {
+
voiceChannel.createInvite()
.setTargetApplication(applicationId)
.setMaxUses(maxUses)
- .setMaxAge(maxAge)
+ .setMaxAge(maxAgeDays == null ? null
+ : Math.toIntExact(TimeUnit.DAYS.toSeconds(maxAgeDays)))
.flatMap(invite -> replyInvite(event, invite, applicationName))
.queue(null, throwable -> handleErrors(event, throwable));
+
}
private static @NotNull ReplyAction replyInvite(@NotNull SlashCommandEvent event,
@@ -223,51 +215,16 @@ private static void handleErrors(@NotNull SlashCommandEvent event,
logger.warn("Something went wrong in the VcActivityCommand", throwable);
}
-
/**
- * This grabs the OptionMapping, after this it
- * - validates whenever it's within an {@link Integer Integer's} range
- * - validates whenever it's positive
- *
- *
- *
- *
- * @param event the {@link SlashCommandEvent}
- * @param optionMapping the {@link OptionMapping}
- * @return nullable {@link Integer}
- * @throws java.lang.IllegalArgumentException if the option's value is - outside of
- * {@link Integer#MAX_VALUE} - negative
- */
- @Contract("_, null -> null")
- private static @Nullable Integer handleIntegerTypeOption(@NotNull SlashCommandEvent event,
- @Nullable OptionMapping optionMapping) {
-
- int optionValue;
-
- if (optionMapping == null) {
- return null;
- }
-
- try {
- optionValue = Math.toIntExact(optionMapping.getAsLong());
- } catch (ArithmeticException e) {
- event
- .reply("The " + optionMapping.getName() + " is above `" + Integer.MAX_VALUE
- + "`, which is too high")
- .setEphemeral(true)
- .queue();
- throw new IllegalArgumentException(
- optionMapping.getName() + " can't be above " + Integer.MAX_VALUE);
- }
-
- if (optionValue < 0) {
- event.reply("The " + optionMapping.getName() + " is negative, which isn't supported")
- .setEphemeral(true)
- .queue();
- throw new IllegalArgumentException(optionMapping.getName() + " can't be negative");
- }
+ * Interprets the given option as integer. Throws if the option is not an integer.
+ *
+ * @param option the option that contains the integer to extract, or null if not present
+ * @return the extracted integer if present, null otherwise
+ **/
+ @Contract("null -> null")
+ private static @Nullable Integer requireIntOptionIfPresent(@Nullable OptionMapping option) {
+ return option == null ? null : Math.toIntExact(option.getAsLong());
- return optionValue;
}
}