1919import org .slf4j .LoggerFactory ;
2020import org .togetherjava .tjbot .commands .SlashCommandAdapter ;
2121import org .togetherjava .tjbot .commands .SlashCommandVisibility ;
22-
2322import java .util .List ;
2423import java .util .Map ;
2524import java .util .Objects ;
2625import java .util .Optional ;
26+ import java .util .concurrent .TimeUnit ;
27+
2728
2829/**
2930 * Implements the {@code vc-activity} command. Creates VC activities.
@@ -45,6 +46,9 @@ public final class VcActivityCommand extends SlashCommandAdapter {
4546 private static final String MAX_USES_OPTION = "max-uses" ;
4647 private static final String MAX_AGE_OPTION = "max-age" ;
4748
49+ private static final long MAX_AGE_DAYS_LIMIT = 7 ;
50+ private static final long MAX_USES_LIMIT = 100 ;
51+
4852 public static final String YOUTUBE_TOGETHER_NAME = "YouTube Together" ;
4953 public static final String POKER_NAME = "Poker" ;
5054 public static final String BETRAYAL_IO_NAME = "Betrayal.io" ;
@@ -69,7 +73,6 @@ public final class VcActivityCommand extends SlashCommandAdapter {
6973 new Command .Choice (WORDSNACK_NAME , WORDSNACK_NAME ),
7074 new Command .Choice (LETTERTILE_NAME , LETTERTILE_NAME ));
7175
72-
7376 /**
7477 * List comes from <a href="https://github.com/DV8FromTheWorld/JDA/pull/1628">the "Implement
7578 * invite targets" PR on JDA</a>. There is no official list from Discord themselves, so this is
@@ -82,12 +85,15 @@ public final class VcActivityCommand extends SlashCommandAdapter {
8285 "852509694341283871" , DOODLECREW_NAME , "878067389634314250" , WORDSNACK_NAME ,
8386 "879863976006127627" , LETTERTILE_NAME , "879863686565621790" );
8487
85- private static final List <OptionData > inviteOptions = List .of (
86- new OptionData (OptionType .STRING , MAX_USES_OPTION ,
87- "The amount of times the invite can be used, default is infinity" , false ),
88+ private static final List <OptionData > inviteOptions = List .of (new OptionData (OptionType .INTEGER ,
89+ MAX_USES_OPTION ,
90+ "How many times this invite can be used, 0 infinite (default) - %d being the highest."
91+ .formatted (MAX_USES_LIMIT ),
92+ false ).setRequiredRange (0 , MAX_USES_LIMIT ),
8893 new OptionData (OptionType .INTEGER , MAX_AGE_OPTION ,
89- "Max age in seconds. Set this to 0 to never expire, default is 1 day" , false ));
90-
94+ "How long, in days this activity can be used before it expires, 0 (No expiry), Max is %d days."
95+ .formatted (MAX_AGE_DAYS_LIMIT ),
96+ false ).setRequiredRange (0 , MAX_AGE_DAYS_LIMIT ));
9197
9298 /**
9399 * Constructs an instance
@@ -148,29 +154,10 @@ public void onSlashCommand(@NotNull SlashCommandEvent event) {
148154 OptionMapping maxUsesOption = event .getOption (MAX_USES_OPTION );
149155 OptionMapping maxAgeOption = event .getOption (MAX_AGE_OPTION );
150156
151- Integer maxUses ;
152-
153- // the user already received the error in the handleIntegerTypeOption method
154- // it still throws to tell us to return this method and stop the proceeding code
155- try {
156- maxUses = handleIntegerTypeOption (event , maxUsesOption );
157- } catch (IllegalArgumentException ignore ) {
158- return ;
159- }
160-
161- Integer maxAge ;
162-
163- // the user already received the error in the handleIntegerTypeOption method
164- // it still throws to tell us to return this method and stop the proceeding code
165- try {
166- maxAge = handleIntegerTypeOption (event , maxAgeOption );
167- } catch (IllegalArgumentException ignore ) {
168- return ;
169- }
170-
171-
172157 String applicationId ;
173158 String applicationName ;
159+ Integer maxUses = requireIntOptionIfPresent (maxUsesOption );
160+ Integer maxAgeDays = requireIntOptionIfPresent (maxAgeOption );
174161
175162 if (applicationOption != null ) {
176163 applicationName = applicationOption .getAsString ();
@@ -182,9 +169,10 @@ public void onSlashCommand(@NotNull SlashCommandEvent event) {
182169 getKeyByValue (VC_APPLICATION_TO_ID , applicationId ).orElse ("an activity" );
183170 }
184171
185- handleSubcommand (event , voiceChannel , applicationId , maxUses , maxAge , applicationName );
172+ handleSubcommand (event , voiceChannel , applicationId , maxUses , maxAgeDays , applicationName );
186173 }
187174
175+
188176 private static <K , V > @ NotNull Optional <K > getKeyByValue (@ NotNull Map <K , V > map ,
189177 @ NotNull V value ) {
190178 for (Map .Entry <K , V > entry : map .entrySet ()) {
@@ -198,14 +186,18 @@ public void onSlashCommand(@NotNull SlashCommandEvent event) {
198186
199187 private static void handleSubcommand (@ NotNull SlashCommandEvent event ,
200188 @ NotNull VoiceChannel voiceChannel , @ NotNull String applicationId ,
201- @ Nullable Integer maxUses , @ Nullable Integer maxAge , @ NotNull String applicationName ) {
189+ @ Nullable Integer maxUses , @ Nullable Integer maxAgeDays ,
190+ @ NotNull String applicationName ) {
191+
202192
203193 voiceChannel .createInvite ()
204194 .setTargetApplication (applicationId )
205195 .setMaxUses (maxUses )
206- .setMaxAge (maxAge )
196+ .setMaxAge (maxAgeDays == null ? null
197+ : Math .toIntExact (TimeUnit .DAYS .toSeconds (maxAgeDays )))
207198 .flatMap (invite -> replyInvite (event , invite , applicationName ))
208199 .queue (null , throwable -> handleErrors (event , throwable ));
200+
209201 }
210202
211203 private static @ NotNull ReplyAction replyInvite (@ NotNull SlashCommandEvent event ,
@@ -223,51 +215,16 @@ private static void handleErrors(@NotNull SlashCommandEvent event,
223215 logger .warn ("Something went wrong in the VcActivityCommand" , throwable );
224216 }
225217
226-
227218 /**
228- * This grabs the OptionMapping, after this it <br />
229- * - validates whenever it's within an {@link Integer Integer's} range <br />
230- * - validates whenever it's positive <br />
231- *
232- * <p>
233- * <p/>
234- *
235- * @param event the {@link SlashCommandEvent}
236- * @param optionMapping the {@link OptionMapping}
237- * @return nullable {@link Integer}
238- * @throws java.lang.IllegalArgumentException if the option's value is - outside of
239- * {@link Integer#MAX_VALUE} - negative
240- */
241- @ Contract ("_, null -> null" )
242- private static @ Nullable Integer handleIntegerTypeOption (@ NotNull SlashCommandEvent event ,
243- @ Nullable OptionMapping optionMapping ) {
244-
245- int optionValue ;
246-
247- if (optionMapping == null ) {
248- return null ;
249- }
250-
251- try {
252- optionValue = Math .toIntExact (optionMapping .getAsLong ());
253- } catch (ArithmeticException e ) {
254- event
255- .reply ("The " + optionMapping .getName () + " is above `" + Integer .MAX_VALUE
256- + "`, which is too high" )
257- .setEphemeral (true )
258- .queue ();
259- throw new IllegalArgumentException (
260- optionMapping .getName () + " can't be above " + Integer .MAX_VALUE );
261- }
262-
263- if (optionValue < 0 ) {
264- event .reply ("The " + optionMapping .getName () + " is negative, which isn't supported" )
265- .setEphemeral (true )
266- .queue ();
267- throw new IllegalArgumentException (optionMapping .getName () + " can't be negative" );
268- }
219+ * Interprets the given option as integer. Throws if the option is not an integer.
220+ *
221+ * @param option the option that contains the integer to extract, or null if not present
222+ * @return the extracted integer if present, null otherwise
223+ **/
224+ @ Contract ("null -> null" )
225+ private static @ Nullable Integer requireIntOptionIfPresent (@ Nullable OptionMapping option ) {
269226
227+ return option == null ? null : Math .toIntExact (option .getAsLong ());
270228
271- return optionValue ;
272229 }
273230}
0 commit comments