diff --git a/src/main/java/dev/qixils/quasicord/commands/UserConfigCommand.java b/src/main/java/dev/qixils/quasicord/commands/UserConfigCommand.java index b226074..a77f199 100644 --- a/src/main/java/dev/qixils/quasicord/commands/UserConfigCommand.java +++ b/src/main/java/dev/qixils/quasicord/commands/UserConfigCommand.java @@ -75,7 +75,7 @@ public Mono setTimeZoneCommand( Channel channel ) { var collection = library.getDatabaseManager().collection(TimeZoneConfig.class); - var filter = eq("id", user.getIdLong()); + var filter = eq("_id", user.getIdLong()); Publisher result; if (tz == null) { result = collection.deleteOne(filter); diff --git a/src/main/java/dev/qixils/quasicord/db/CollectionName.java b/src/main/java/dev/qixils/quasicord/db/CollectionName.java index 981f39d..cdd0cc6 100644 --- a/src/main/java/dev/qixils/quasicord/db/CollectionName.java +++ b/src/main/java/dev/qixils/quasicord/db/CollectionName.java @@ -16,5 +16,5 @@ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface CollectionName { - @NonNull String name(); + @NonNull String value(); } diff --git a/src/main/java/dev/qixils/quasicord/db/DatabaseManager.java b/src/main/java/dev/qixils/quasicord/db/DatabaseManager.java index 0b831c5..c12e390 100644 --- a/src/main/java/dev/qixils/quasicord/db/DatabaseManager.java +++ b/src/main/java/dev/qixils/quasicord/db/DatabaseManager.java @@ -62,7 +62,7 @@ private static String collectionNameOf(Object object) { private static String collectionNameOf(Class clazz) { String collectionName; if (clazz.isAnnotationPresent(CollectionName.class)) - collectionName = clazz.getAnnotation(CollectionName.class).name(); + collectionName = clazz.getAnnotation(CollectionName.class).value(); else collectionName = clazz.getSimpleName(); return collectionName.substring(0, Math.min(collectionName.length(), 127)); diff --git a/src/main/java/dev/qixils/quasicord/db/collection/LocaleConfig.java b/src/main/java/dev/qixils/quasicord/db/collection/LocaleConfig.java index f15fd90..9176152 100644 --- a/src/main/java/dev/qixils/quasicord/db/collection/LocaleConfig.java +++ b/src/main/java/dev/qixils/quasicord/db/collection/LocaleConfig.java @@ -19,7 +19,7 @@ * An entry in the locale configuration database collection. * This stores the selected locale for a user, channel, or guild. */ -@CollectionName(name = "locale") +@CollectionName("locale") public class LocaleConfig { @BsonId diff --git a/src/main/java/dev/qixils/quasicord/db/collection/TimeZoneConfig.java b/src/main/java/dev/qixils/quasicord/db/collection/TimeZoneConfig.java index 5e6434b..caaa009 100644 --- a/src/main/java/dev/qixils/quasicord/db/collection/TimeZoneConfig.java +++ b/src/main/java/dev/qixils/quasicord/db/collection/TimeZoneConfig.java @@ -19,7 +19,7 @@ * An entry in the timezone configuration database collection. * This stores the selected timezone for a user. */ -@CollectionName(name = "timezone") +@CollectionName("timezone") public class TimeZoneConfig { @BsonId diff --git a/src/main/java/dev/qixils/quasicord/decorators/ParserCommand.java b/src/main/java/dev/qixils/quasicord/decorators/ParserCommand.java index da0538a..a387fee 100644 --- a/src/main/java/dev/qixils/quasicord/decorators/ParserCommand.java +++ b/src/main/java/dev/qixils/quasicord/decorators/ParserCommand.java @@ -67,8 +67,8 @@ public static void consumeCommandResult(@NonNull CommandInteraction interaction, case Mono mono -> mono.subscribe(res -> consumeCommandResult(interaction, res)); case CompletableFuture fut -> fut.thenAccept(res -> consumeCommandResult(interaction, res)); // terminal cases: - case null -> interaction.deferReply().queue(); - case Boolean ephemeral -> interaction.deferReply(ephemeral).queue(); + case null -> {} + case Boolean ephemeral -> interaction.deferReply(ephemeral).queue(); // TODO: replace with little enum class? case QuasiMessage message -> message.text().asString(Context.fromInteraction(interaction)).subscribe(string -> { var action = interaction.reply(string); message.modifier().accept(action); diff --git a/src/main/java/dev/qixils/quasicord/locale/Context.java b/src/main/java/dev/qixils/quasicord/locale/Context.java index 03efb9f..bd5b6aa 100644 --- a/src/main/java/dev/qixils/quasicord/locale/Context.java +++ b/src/main/java/dev/qixils/quasicord/locale/Context.java @@ -6,8 +6,6 @@ package dev.qixils.quasicord.locale; -import dev.qixils.quasicord.locale.impl.ImmutableContextImpl; -import dev.qixils.quasicord.locale.impl.MutableContextImpl; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Message; @@ -26,10 +24,6 @@ * Stores information about the author and location of a message to determine the {@link Locale} * to use for localizing response messages. */ -// TODO: discord now exposes the user's selected locale in the slash command event object. -// this should be checked after the user config check but before the channel config check. -// TODO: discord also exposes the guild's locale! that should be checked after the guild config check. -// TODO: the interface should not be pseudo-mutable... it should be immutable with a mutable builder. public interface Context { /** @@ -42,13 +36,6 @@ public interface Context { return localeProvider.forContext(this); } - /** - * Determines if this context is mutable. - * - * @return true if this context is mutable - */ - boolean isMutable(); - // getters /** @@ -86,149 +73,24 @@ public interface Context { */ @Nullable DiscordLocale guildLocale(); - // user setter - - /** - * Sets the user ID of this context. - * - * @param user the user ID - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - @NonNull Context user(long user); - - /** - * Sets the user ID of this context. - * - * @param user the user - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - default @NonNull Context user(@NonNull User user) { - return user(Objects.requireNonNull(user, "user").getIdLong()); - } - - /** - * Sets the user ID of this context. - * - * @param member the member - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - default @NonNull Context user(@NonNull Member member) { - return user(Objects.requireNonNull(member, "member").getIdLong()); - } - - // user locale setter - - /** - * Sets the user locale of this context. - * - * @param locale the locale - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - @NonNull Context userLocale(@Nullable DiscordLocale locale); - - /** - * Sets the user locale of this context. - * - * @param interaction an interaction triggered by the user - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - default @NonNull Context userLocale(@NonNull Interaction interaction) { - return userLocale(Objects.requireNonNull(interaction, "interaction").getUserLocale()); - } - - // channel setter - - /** - * Sets the channel ID of this context. - * - * @param channel the channel ID - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - @NonNull Context channel(long channel); - - /** - * Sets the channel ID of this context. - * - * @param channel the channel - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - default @NonNull Context channel(@NonNull MessageChannel channel) { - return channel(Objects.requireNonNull(channel, "channel").getIdLong()); - } - - // guild setter - - /** - * Sets the guild ID of this context. - * - * @param guild the guild ID - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - @NonNull Context guild(long guild); - - /** - * Sets the guild ID of this context. - * - * @param guild the guild - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - default @NonNull Context guild(@NonNull Guild guild) { - return guild(Objects.requireNonNull(guild, "guild").getIdLong()); - } - - // guild locale setter - - /** - * Sets the guild locale of this context. - * - * @param locale the locale - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - @NonNull Context guildLocale(@Nullable DiscordLocale locale); - - /** - * Sets the guild locale of this context. - * - * @param guild the guild - * @return this context - * @throws UnsupportedOperationException if this context is immutable - */ - default @NonNull Context guildLocale(@NonNull Guild guild) { - Objects.requireNonNull(guild, "guild"); - DiscordLocale locale = guild.getFeatures().contains("COMMUNITY") - ? guild.getLocale() - : null; - return guildLocale(locale); - } - // copy /** - * Creates a mutable copy of this context. + * Creates a {@link Builder} from this context. * - * @return a mutable copy of this context + * @return a builder from this context */ - default @NonNull Context mutableCopy() { - return new MutableContextImpl(user(), userLocale(), channel(), guild(), guildLocale()); + default @NonNull Context toBuilder() { + return builder().user(user()).userLocale(userLocale()).channel(channel()).guild(guild()).guildLocale(guildLocale()).build(); } /** - * Creates an immutable copy of this context. + * Creates a new {@link Builder}. * - * @return an immutable copy of this context + * @return new builder */ - default @NonNull Context immutableCopy() { - return new ImmutableContextImpl(user(), userLocale(), channel(), guild(), guildLocale()); + static @NonNull Builder builder() { + return new ContextBuilderImpl(); } /** @@ -238,12 +100,12 @@ public interface Context { * @return a context */ static @NonNull Context fromMessage(@NonNull Message message) { - Context context = new MutableContextImpl() + Builder context = builder() .user(message.getAuthor()) .channel(message.getChannel()); if (message.isFromGuild()) context.guild(message.getGuild()).guildLocale(message.getGuild()); - return context.immutableCopy(); + return context.build(); } /** @@ -253,16 +115,142 @@ public interface Context { * @return a context */ static @NonNull Context fromInteraction(@NonNull Interaction interaction) { - Context context = new MutableContextImpl().user(interaction.getUser()); + Builder context = new ContextBuilderImpl().user(interaction.getUser()); if (interaction.getChannel() instanceof MessageChannel channel) context.channel(channel); if (interaction.getGuild() != null) context.guild(interaction.getGuild()).guildLocale(interaction.getGuild()); - return context.immutableCopy(); + return context.build(); } /** * An empty context. */ - @NonNull Context EMPTY = new ImmutableContextImpl(0, null, 0, 0, null); + @NonNull Context EMPTY = builder().build(); + + /** + * Builder for a {@link Context}. + */ + @SuppressWarnings("UnusedReturnValue") + interface Builder { + + // user setter + + /** + * Sets the user ID of this context. + * + * @param user the user ID + * @return this context + */ + @NonNull Builder user(long user); + + /** + * Sets the user ID of this context. + * + * @param user the user + * @return this context + */ + default @NonNull Builder user(@NonNull User user) { + return user(Objects.requireNonNull(user, "user").getIdLong()); + } + + /** + * Sets the user ID of this context. + * + * @param member the member + * @return this context + */ + default @NonNull Builder user(@NonNull Member member) { + return user(Objects.requireNonNull(member, "member").getIdLong()); + } + + // user locale setter + + /** + * Sets the user locale of this context. + * + * @param locale the locale + * @return this context + */ + @NonNull Builder userLocale(@Nullable DiscordLocale locale); + + /** + * Sets the user locale of this context. + * + * @param interaction an interaction triggered by the user + * @return this context + */ + default @NonNull Builder userLocale(@NonNull Interaction interaction) { + return userLocale(Objects.requireNonNull(interaction, "interaction").getUserLocale()); + } + + // channel setter + + /** + * Sets the channel ID of this context. + * + * @param channel the channel ID + * @return this context + */ + @NonNull Builder channel(long channel); + + /** + * Sets the channel ID of this context. + * + * @param channel the channel + * @return this context + */ + default @NonNull Builder channel(@NonNull MessageChannel channel) { + return channel(Objects.requireNonNull(channel, "channel").getIdLong()); + } + + // guild setter + + /** + * Sets the guild ID of this context. + * + * @param guild the guild ID + * @return this context + */ + @NonNull Builder guild(long guild); + + /** + * Sets the guild ID of this context. + * + * @param guild the guild + * @return this context + */ + default @NonNull Builder guild(@NonNull Guild guild) { + return guild(Objects.requireNonNull(guild, "guild").getIdLong()); + } + + // guild locale setter + + /** + * Sets the guild locale of this context. + * + * @param locale the locale + * @return this context + */ + @NonNull Builder guildLocale(@Nullable DiscordLocale locale); + + /** + * Sets the guild locale of this context. + * + * @param guild the guild + * @return this context + */ + default @NonNull Builder guildLocale(@NonNull Guild guild) { + Objects.requireNonNull(guild, "guild"); + DiscordLocale locale = guild.getFeatures().contains("COMMUNITY") + ? guild.getLocale() + : null; + return guildLocale(locale); + } + + /** + * Builds the {@link Context}. + */ + @NonNull Context build(); + } } diff --git a/src/main/java/dev/qixils/quasicord/locale/impl/MutableContextImpl.java b/src/main/java/dev/qixils/quasicord/locale/ContextBuilderImpl.java similarity index 50% rename from src/main/java/dev/qixils/quasicord/locale/impl/MutableContextImpl.java rename to src/main/java/dev/qixils/quasicord/locale/ContextBuilderImpl.java index 5675d8d..e6174c9 100644 --- a/src/main/java/dev/qixils/quasicord/locale/impl/MutableContextImpl.java +++ b/src/main/java/dev/qixils/quasicord/locale/ContextBuilderImpl.java @@ -4,23 +4,19 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -package dev.qixils.quasicord.locale.impl; +package dev.qixils.quasicord.locale; -import dev.qixils.quasicord.locale.Context; -import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import net.dv8tion.jda.api.interactions.DiscordLocale; +import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import java.util.Objects; - @Accessors(fluent = true, chain = true) -@AllArgsConstructor @NoArgsConstructor @Data -public final class MutableContextImpl implements Context { +final class ContextBuilderImpl implements Context.Builder { private long user; private @Nullable DiscordLocale userLocale; private long channel; @@ -28,20 +24,7 @@ public final class MutableContextImpl implements Context { private @Nullable DiscordLocale guildLocale; @Override - public boolean isMutable() { - return true; - } - - @Override - public int hashCode() { - return Objects.hash(user, userLocale, channel, guild, guildLocale); - } - - public boolean equals(@Nullable Object obj) { - if (obj == null) return false; - if (!(obj instanceof Context other)) return false; - if (user != other.user()) return false; - if (channel != other.channel()) return false; - return guild == other.guild(); + public @NonNull Context build() { + return new ContextImpl(user, userLocale, channel, guild, guildLocale); } } diff --git a/src/main/java/dev/qixils/quasicord/locale/ContextImpl.java b/src/main/java/dev/qixils/quasicord/locale/ContextImpl.java new file mode 100644 index 0000000..59facaf --- /dev/null +++ b/src/main/java/dev/qixils/quasicord/locale/ContextImpl.java @@ -0,0 +1,20 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package dev.qixils.quasicord.locale; + +import net.dv8tion.jda.api.interactions.DiscordLocale; +import org.checkerframework.checker.nullness.qual.Nullable; + +record ContextImpl( + long user, + @Nullable DiscordLocale userLocale, + long channel, + long guild, + @Nullable DiscordLocale guildLocale +) implements Context { +} + diff --git a/src/main/java/dev/qixils/quasicord/locale/impl/ImmutableContextImpl.java b/src/main/java/dev/qixils/quasicord/locale/impl/ImmutableContextImpl.java deleted file mode 100644 index ad641ad..0000000 --- a/src/main/java/dev/qixils/quasicord/locale/impl/ImmutableContextImpl.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -package dev.qixils.quasicord.locale.impl; - -import dev.qixils.quasicord.locale.Context; -import net.dv8tion.jda.api.interactions.DiscordLocale; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.jetbrains.annotations.NotNull; - -public record ImmutableContextImpl( - long user, - @Nullable DiscordLocale userLocale, - long channel, - long guild, - @Nullable DiscordLocale guildLocale -) implements Context { - - @Override - public boolean isMutable() { - return false; - } - - @Override - public @NotNull Context user(long user) { - throw new UnsupportedOperationException(); - } - - @Override - public @NonNull Context userLocale(@Nullable DiscordLocale locale) { - throw new UnsupportedOperationException(); - } - - @Override - public @NotNull Context channel(long channel) { - throw new UnsupportedOperationException(); - } - - @Override - public @NotNull Context guild(long guild) { - throw new UnsupportedOperationException(); - } - - @Override - public @NonNull Context guildLocale(@Nullable DiscordLocale locale) { - throw new UnsupportedOperationException(); - } -} -