[AB-xxx] adding support to use @time inputs for duration and instant command parameters

This commit is contained in:
Sheldan
2026-02-15 22:44:57 +01:00
parent 2f125d0101
commit fa62353aee
7 changed files with 93 additions and 20 deletions

View File

@@ -130,13 +130,14 @@ public class RemindServiceBean implements ReminderService {
if(remindIn.getSeconds() < 60) {
reminder.setJobTriggerKey(null);
log.info("Directly scheduling unremind for reminder {}, because it was below the threshold.", reminder.getId());
long nanos = Math.max(remindIn.toNanos(), Duration.ofSeconds(5).toNanos()); // should be good enough, if its too small, it doesnt find the reminder
instantReminderScheduler.schedule(() -> {
try {
self.executeReminder(reminder.getId());
} catch (Exception exception) {
log.error("Failed to remind immediately.", exception);
}
}, remindIn.toNanos(), TimeUnit.NANOSECONDS);
}, nanos, TimeUnit.NANOSECONDS);
} else {
HashMap<Object, Object> parameters = new HashMap<>();
parameters.put("reminderId", reminder.getId().toString());

View File

@@ -15,7 +15,7 @@ public class InstantSlashCommandParameterProvider implements SlashCommandParamet
return SlashCommandOptionTypeMapping
.builder()
.type(Instant.class)
.optionTypes(Arrays.asList(OptionType.INTEGER))
.optionTypes(Arrays.asList(OptionType.STRING))
.build();
}
}

View File

@@ -10,11 +10,11 @@ public class DurationFormatException extends AbstractoRunTimeException implement
private final DurationFormatExceptionModel model;
public DurationFormatException(String wrongFormat, List<String> validFormats) {
public DurationFormatException(String invalidFormat, List<String> validFormats) {
super("Duration format exception ");
this.model = DurationFormatExceptionModel
.builder()
.invalidFormat(wrongFormat)
.invalidFormat(invalidFormat)
.validFormats(validFormats)
.build();
}

View File

@@ -0,0 +1,28 @@
package dev.sheldan.abstracto.core.exception;
import dev.sheldan.abstracto.core.models.exception.InstantFormatExceptionModel;
import dev.sheldan.abstracto.core.templating.Templatable;
public class InstantFormatException extends AbstractoRunTimeException implements Templatable {
private final InstantFormatExceptionModel model;
public InstantFormatException(String invalidFormat) {
super("Instant format exception ");
this.model = InstantFormatExceptionModel
.builder()
.invalidFormat(invalidFormat)
.build();
}
@Override
public String getTemplateName() {
return "instant_invalid_time_format_exception";
}
@Override
public Object getTemplateModel() {
return model;
}
}

View File

@@ -0,0 +1,13 @@
package dev.sheldan.abstracto.core.models.exception;
import java.io.Serializable;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@Builder
public class InstantFormatExceptionModel implements Serializable {
private final String invalidFormat;
}

View File

@@ -3,12 +3,18 @@ package dev.sheldan.abstracto.core.utils;
import dev.sheldan.abstracto.core.command.exception.AbstractoTemplatedException;
import dev.sheldan.abstracto.core.exception.DurationFormatException;
import dev.sheldan.abstracto.core.exception.InstantFormatException;
import java.time.Instant;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.ISnowflake;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.utils.TimeFormat;
import net.dv8tion.jda.api.utils.Timestamp;
import net.dv8tion.jda.api.utils.cache.SnowflakeCacheView;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import java.time.Duration;
@@ -18,40 +24,65 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
public class ParseUtils {
private ParseUtils() {
}
private static Pattern messageRegex = Pattern.compile("(?<number>\\d+)(?<unit>[ywdhms]+)");
private static List<String> validDuration = Arrays.asList("w", "d", "h", "m", "s");
private static final Pattern MESSAGE_REGEX = Pattern.compile("(?<number>\\d+)(?<unit>[ywdhms]+)");
private static final List<String> VALID_DURATION = Arrays.asList("w", "d", "h", "m", "s");
public static Duration parseDuration(String textToParseFrom) {
if(textToParseFrom == null || textToParseFrom.isEmpty()) {
throw new DurationFormatException("", validDuration);
throw new DurationFormatException("", VALID_DURATION);
}
Matcher matcher = ParseUtils.messageRegex.matcher(textToParseFrom);
Duration start = Duration.ZERO;
Duration targetDuration;
try {
Timestamp discordTimeStamp = TimeFormat.parse(textToParseFrom);
targetDuration = Duration.between(Instant.now(), discordTimeStamp.toInstant());
return targetDuration;
} catch (IllegalArgumentException ex) {
// ignore
}
Matcher matcher = ParseUtils.MESSAGE_REGEX.matcher(textToParseFrom);
targetDuration = Duration.ZERO;
String rest = textToParseFrom;
while(matcher.find()) {
String unit = matcher.group("unit");
String number = matcher.group("number");
rest = rest.replace(matcher.group(0), "");
long parsed = Long.parseLong(number);
switch (unit) {
case "w": start = start.plus(Duration.ofDays(parsed * 7)); break;
case "d": start = start.plus(Duration.ofDays(parsed)); break;
case "h": start = start.plus(Duration.ofHours(parsed)); break;
case "m": start = start.plus(Duration.ofMinutes(parsed)); break;
case "s": start = start.plus(Duration.ofSeconds(parsed)); break;
default: throw new DurationFormatException(unit, validDuration);
}
targetDuration = switch (unit) {
case "w" -> targetDuration.plus(Duration.ofDays(parsed * 7));
case "d" -> targetDuration.plus(Duration.ofDays(parsed));
case "h" -> targetDuration.plus(Duration.ofHours(parsed));
case "m" -> targetDuration.plus(Duration.ofMinutes(parsed));
case "s" -> targetDuration.plus(Duration.ofSeconds(parsed));
default -> throw new DurationFormatException(unit, VALID_DURATION);
};
}
if(!rest.equals("")) {
throw new DurationFormatException(rest, validDuration);
throw new DurationFormatException(rest, VALID_DURATION);
}
return start;
return targetDuration;
}
public static Instant parseInstant(String textToParseFrom) {
if(textToParseFrom == null || textToParseFrom.isEmpty()) {
throw new DurationFormatException("", VALID_DURATION);
}
try {
Timestamp discordTimeStamp = TimeFormat.parse(textToParseFrom);
return discordTimeStamp.toInstant();
} catch (IllegalArgumentException ex) {
// ignore
}
if(StringUtils.isNumeric(textToParseFrom)) {
return Instant.ofEpochSecond(Integer.parseInt(textToParseFrom));
}
throw new InstantFormatException(textToParseFrom);
}
public static Role parseRoleFromText(String text, Guild guild) {

View File

@@ -55,7 +55,7 @@
<properties>
<maven.build.timestamp.format>yyyy/MM/dd HH:mm</maven.build.timestamp.format>
<jda.version>6.2.0</jda.version>
<jda.version>6.3.1</jda.version>
<asciidoctor.maven.plugin.version>2.2.6</asciidoctor.maven.plugin.version>
<asciidoctorj.pdf.version>1.5.3</asciidoctorj.pdf.version>
<asciidoctorj.version>2.3.0</asciidoctorj.version>