diff --git a/application/build.gradle b/application/build.gradle index c36956258d..80b59cb2a8 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -39,6 +39,7 @@ shadowJar { } dependencies { + implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'org.jetbrains:annotations:23.0.0' implementation project(':database') diff --git a/application/src/main/java/org/togetherjava/tjbot/Application.java b/application/src/main/java/org/togetherjava/tjbot/Application.java index 73b0b6be1a..fed19cc192 100644 --- a/application/src/main/java/org/togetherjava/tjbot/Application.java +++ b/application/src/main/java/org/togetherjava/tjbot/Application.java @@ -2,20 +2,17 @@ import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; -import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import org.jetbrains.annotations.NotNull; +import net.dv8tion.jda.api.requests.GatewayIntent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.togetherjava.tjbot.commands.Features; +import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.system.BotCore; import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.db.Database; -import org.togetherjava.tjbot.commands.SlashCommandAdapter; import javax.security.auth.login.LoginException; - import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -114,8 +111,7 @@ private static void onShutdown() { logger.info("Bot has been stopped"); } - private static void onUncaughtException(@NotNull Thread failingThread, - @NotNull Throwable failure) { + private static void onUncaughtException(Thread failingThread, Throwable failure) { logger.error("Unknown error in thread {}.", failingThread.getName(), failure); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java index 4a1f831fe2..0826682c08 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java @@ -1,7 +1,6 @@ package org.togetherjava.tjbot.commands; import net.dv8tion.jda.api.JDA; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.basic.PingCommand; import org.togetherjava.tjbot.commands.basic.RoleSelectCommand; import org.togetherjava.tjbot.commands.basic.SuggestionsUpDownVoter; @@ -32,6 +31,7 @@ import org.togetherjava.tjbot.moderation.ModAuditLogWriter; import org.togetherjava.tjbot.routines.ModAuditLogRoutine; +import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Collection; @@ -59,8 +59,8 @@ private Features() { * @param config the configuration features should use * @return a collection of all features */ - public static @NotNull Collection createFeatures(@NotNull JDA jda, - @NotNull Database database, @NotNull Config config) { + @Nonnull + public static Collection createFeatures(JDA jda, Database database, Config config) { TagSystem tagSystem = new TagSystem(database); ModerationActionsStore actionsStore = new ModerationActionsStore(database); ModAuditLogWriter modAuditLogWriter = new ModAuditLogWriter(config); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java index ee679a47f0..c99e08cf98 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java @@ -2,8 +2,8 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; import java.util.regex.Pattern; /** @@ -28,7 +28,7 @@ public interface MessageReceiver extends Feature { * * @return the pattern matching the names of relevant channels */ - @NotNull + @Nonnull Pattern getChannelNamePattern(); /** @@ -38,7 +38,7 @@ public interface MessageReceiver extends Feature { * @param event the event that triggered this, containing information about the corresponding * message that was sent and received */ - void onMessageReceived(@NotNull MessageReceivedEvent event); + void onMessageReceived(MessageReceivedEvent event); /** * Triggered by the core system whenever an existing message was edited in a text channel of a @@ -47,5 +47,5 @@ public interface MessageReceiver extends Feature { * @param event the event that triggered this, containing information about the corresponding * message that was edited */ - void onMessageUpdated(@NotNull MessageUpdateEvent event); + void onMessageUpdated(MessageUpdateEvent event); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java index 3d13b3b3e9..b2be566758 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java @@ -2,8 +2,8 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; import java.util.regex.Pattern; /** @@ -24,24 +24,25 @@ public abstract class MessageReceiverAdapter implements MessageReceiver { * @param channelNamePattern the pattern matching names of channels interested in, only messages * from matching channels will be received */ - protected MessageReceiverAdapter(@NotNull Pattern channelNamePattern) { + protected MessageReceiverAdapter(Pattern channelNamePattern) { this.channelNamePattern = channelNamePattern; } @Override - public final @NotNull Pattern getChannelNamePattern() { + @Nonnull + public final Pattern getChannelNamePattern() { return channelNamePattern; } @SuppressWarnings("NoopMethodInAbstractClass") @Override - public void onMessageReceived(@NotNull MessageReceivedEvent event) { + public void onMessageReceived(MessageReceivedEvent event) { // Adapter does not react by default, subclasses may change this behavior } @SuppressWarnings("NoopMethodInAbstractClass") @Override - public void onMessageUpdated(@NotNull MessageUpdateEvent event) { + public void onMessageUpdated(MessageUpdateEvent event) { // Adapter does not react by default, subclasses may change this behavior } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/Routine.java b/application/src/main/java/org/togetherjava/tjbot/commands/Routine.java index 10b8aa9d79..1d684bf6a7 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/Routine.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/Routine.java @@ -1,8 +1,8 @@ package org.togetherjava.tjbot.commands; import net.dv8tion.jda.api.JDA; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; import java.util.concurrent.TimeUnit; /** @@ -24,7 +24,7 @@ public interface Routine extends Feature { * * @return the schedule of this routine */ - @NotNull + @Nonnull Schedule createSchedule(); /** @@ -32,7 +32,7 @@ public interface Routine extends Feature { * * @param jda the JDA instance the bot is operating with */ - void runRoutine(@NotNull JDA jda); + void runRoutine(JDA jda); /** * The schedule of routines. @@ -46,8 +46,7 @@ public interface Routine extends Feature { * @param unit the time unit for both, {@link #initialDuration} and {@link #duration}, e.g. * seconds */ - record Schedule(@NotNull ScheduleMode mode, long initialDuration, long duration, - @NotNull TimeUnit unit) { + record Schedule(ScheduleMode mode, long initialDuration, long duration, TimeUnit unit) { } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java index 20f5c936b7..551e4474ec 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java @@ -9,11 +9,11 @@ import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.components.ComponentInteraction; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.componentids.ComponentId; import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator; import org.togetherjava.tjbot.commands.componentids.Lifespan; +import javax.annotation.Nonnull; import java.util.List; /** @@ -49,7 +49,7 @@ public interface SlashCommand extends UserInteractor { * * @return the description of the command */ - @NotNull + @Nonnull String getDescription(); /** @@ -59,7 +59,7 @@ public interface SlashCommand extends UserInteractor { * * @return the visibility of the command */ - @NotNull + @Nonnull SlashCommandVisibility getVisibility(); /** @@ -77,7 +77,7 @@ public interface SlashCommand extends UserInteractor { * * @return the command data of this command */ - @NotNull + @Nonnull SlashCommandData getData(); /** @@ -118,5 +118,5 @@ public interface SlashCommand extends UserInteractor { * * @param event the event that triggered this */ - void onSlashCommand(@NotNull SlashCommandInteractionEvent event); + void onSlashCommand(SlashCommandInteractionEvent event); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommandAdapter.java b/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommandAdapter.java index 023c808a1d..d0d2ee94c4 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommandAdapter.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommandAdapter.java @@ -9,13 +9,13 @@ import net.dv8tion.jda.api.interactions.commands.build.Commands; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Range; import org.jetbrains.annotations.Unmodifiable; import org.togetherjava.tjbot.commands.componentids.ComponentId; import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator; import org.togetherjava.tjbot.commands.componentids.Lifespan; +import javax.annotation.Nonnull; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -55,7 +55,7 @@ * } * * @Override - * public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + * public void onSlashCommand(SlashCommandInteractionEvent event) { * event.reply("Pong!").queue(); * } * } @@ -80,7 +80,7 @@ public abstract class SlashCommandAdapter implements SlashCommand { * {@link SlashCommandData#setDescription(String)} * @param visibility the visibility of the command */ - protected SlashCommandAdapter(@NotNull String name, @NotNull String description, + protected SlashCommandAdapter(String name, String description, SlashCommandVisibility visibility) { this.name = name; this.description = description; @@ -90,40 +90,43 @@ protected SlashCommandAdapter(@NotNull String name, @NotNull String description, } @Override - public final @NotNull String getName() { + @Nonnull + public final String getName() { return name; } @Override - public final @NotNull String getDescription() { + @Nonnull + public final String getDescription() { return description; } @Override - public final @NotNull SlashCommandVisibility getVisibility() { + @Nonnull + public final SlashCommandVisibility getVisibility() { return visibility; } @Override - public final @NotNull SlashCommandData getData() { + @Nonnull + public final SlashCommandData getData() { return data; } @Override - public final void acceptComponentIdGenerator(@NotNull ComponentIdGenerator generator) { + public final void acceptComponentIdGenerator(ComponentIdGenerator generator) { componentIdGenerator = generator; } @SuppressWarnings("NoopMethodInAbstractClass") @Override - public void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List args) { + public void onButtonClick(ButtonInteractionEvent event, List args) { // Adapter does not react by default, subclasses may change this behavior } @SuppressWarnings("NoopMethodInAbstractClass") @Override - public void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, - @NotNull List args) { + public void onSelectionMenu(SelectMenuInteractionEvent event, List args) { // Adapter does not react by default, subclasses may change this behavior } @@ -142,7 +145,8 @@ public void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, * @return the generated component ID */ @SuppressWarnings("OverloadedVarargsMethod") - protected final @NotNull String generateComponentId(@NotNull String... args) { + @Nonnull + protected final String generateComponentId(String... args) { return generateComponentId(Lifespan.REGULAR, args); } @@ -159,8 +163,8 @@ public void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, * @return the generated component ID */ @SuppressWarnings({"OverloadedVarargsMethod", "WeakerAccess"}) - protected final @NotNull String generateComponentId(@NotNull Lifespan lifespan, - @NotNull String... args) { + @Nonnull + protected final String generateComponentId(Lifespan lifespan, String... args) { return Objects.requireNonNull(componentIdGenerator) .generate(new ComponentId(getName(), Arrays.asList(args)), lifespan); } @@ -190,8 +194,9 @@ public void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, * @return the generated list of options */ @Unmodifiable - protected static @NotNull List generateMultipleOptions( - @NotNull OptionData optionData, @Range(from = 1, to = 25) int amount) { + @Nonnull + protected static List generateMultipleOptions(OptionData optionData, + @Range(from = 1, to = 25) int amount) { String baseName = optionData.getName(); Function nameToOption = @@ -211,8 +216,9 @@ public void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, * @return all options with the given prefix */ @Unmodifiable - protected static @NotNull List getMultipleOptionsByNamePrefix( - @NotNull CommandInteractionPayload event, @NotNull String namePrefix) { + @Nonnull + protected static List getMultipleOptionsByNamePrefix( + CommandInteractionPayload event, String namePrefix) { return event.getOptions() .stream() .filter(option -> option.getName().startsWith(namePrefix)) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/UserInteractor.java b/application/src/main/java/org/togetherjava/tjbot/commands/UserInteractor.java index 4ad0ed0da2..68a916369c 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/UserInteractor.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/UserInteractor.java @@ -3,9 +3,9 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent; import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator; +import javax.annotation.Nonnull; import java.util.List; /** @@ -27,7 +27,7 @@ public interface UserInteractor extends Feature { * * @return the name of the interactor */ - @NotNull + @Nonnull String getName(); /** @@ -49,7 +49,7 @@ public interface UserInteractor extends Feature { * {@link SlashCommand#onSlashCommand(SlashCommandInteractionEvent)} for details on how * these are created */ - void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List args); + void onButtonClick(ButtonInteractionEvent event, List args); /** * Triggered by the core system when a selection menu corresponding to this implementation @@ -70,7 +70,7 @@ public interface UserInteractor extends Feature { * {@link SlashCommand#onSlashCommand(SlashCommandInteractionEvent)} for details on how * these are created */ - void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, @NotNull List args); + void onSelectionMenu(SelectMenuInteractionEvent event, List args); /** * Triggered by the core system during its setup phase. It will provide the interactor a @@ -81,5 +81,5 @@ public interface UserInteractor extends Feature { * * @param generator the provided component id generator */ - void acceptComponentIdGenerator(@NotNull ComponentIdGenerator generator); + void acceptComponentIdGenerator(ComponentIdGenerator generator); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/basic/PingCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/basic/PingCommand.java index 17928dbd7f..fdaba47f5b 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/basic/PingCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/basic/PingCommand.java @@ -1,7 +1,6 @@ package org.togetherjava.tjbot.commands.basic; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; @@ -24,7 +23,7 @@ public PingCommand() { * @param event the corresponding event */ @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { event.reply("Pong!").queue(); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/basic/RoleSelectCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/basic/RoleSelectCommand.java index 0bf97b93f8..be5550bdb9 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/basic/RoleSelectCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/basic/RoleSelectCommand.java @@ -13,13 +13,13 @@ import net.dv8tion.jda.api.interactions.components.selections.SelectMenu; import net.dv8tion.jda.api.interactions.components.selections.SelectOption; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.commands.componentids.Lifespan; +import javax.annotation.Nonnull; import java.awt.Color; import java.util.*; import java.util.function.Function; @@ -80,7 +80,7 @@ public RoleSelectCommand() { } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { if (!handleHasPermissions(event)) { return; } @@ -101,7 +101,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { sendRoleSelectionMenu(event, selectedRoles); } - private boolean handleHasPermissions(@NotNull SlashCommandInteractionEvent event) { + private boolean handleHasPermissions(SlashCommandInteractionEvent event) { if (!event.getMember().hasPermission(Permission.MANAGE_ROLES)) { event.reply("You do not have the required manage role permission to use this command") .setEphemeral(true) @@ -123,7 +123,7 @@ private boolean handleHasPermissions(@NotNull SlashCommandInteractionEvent event } @Contract(pure = true) - private static boolean handleIsBotAccessibleRole(@NotNull Role role) { + private static boolean handleIsBotAccessibleRole(Role role) { boolean isSystemRole = role.isPublicRole() || role.getTags().isBot() || role.getTags().isBoost() || role.getTags().isIntegration(); @@ -135,8 +135,8 @@ private static boolean handleIsBotAccessibleRole(@NotNull Role role) { return !isSystemRole; } - private static boolean handleAccessibleRolesSelected(@NotNull IReplyCallback event, - @NotNull Collection selectedRoles) { + private static boolean handleAccessibleRolesSelected(IReplyCallback event, + Collection selectedRoles) { if (!selectedRoles.isEmpty()) { return true; } @@ -151,8 +151,8 @@ private static boolean handleAccessibleRolesSelected(@NotNull IReplyCallback eve return false; } - private static boolean handleInteractableRolesSelected(@NotNull IReplyCallback event, - @NotNull Collection selectedRoles) { + private static boolean handleInteractableRolesSelected(IReplyCallback event, + Collection selectedRoles) { List nonInteractableRoles = selectedRoles.stream() .filter(role -> !event.getGuild().getSelfMember().canInteract(role)) .toList(); @@ -173,8 +173,8 @@ private static boolean handleInteractableRolesSelected(@NotNull IReplyCallback e return false; } - private void sendRoleSelectionMenu(@NotNull final CommandInteraction event, - @NotNull final Collection selectableRoles) { + private void sendRoleSelectionMenu(final CommandInteraction event, + final Collection selectableRoles) { SelectMenu.Builder menu = SelectMenu.create(generateComponentId(Lifespan.PERMANENT, event.getUser().getId())) .setPlaceholder("Select your roles") @@ -193,8 +193,8 @@ private void sendRoleSelectionMenu(@NotNull final CommandInteraction event, event.replyEmbeds(embed).addActionRow(menu.build()).queue(); } - @NotNull - private static SelectOption mapToSelectOption(@NotNull Role role) { + @Nonnull + private static SelectOption mapToSelectOption(Role role) { RoleIcon roleIcon = role.getIcon(); SelectOption option = SelectOption.of(role.getName(), role.getId()); @@ -206,8 +206,7 @@ private static SelectOption mapToSelectOption(@NotNull Role role) { } @Override - public void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, - @NotNull List args) { + public void onSelectionMenu(SelectMenuInteractionEvent event, List args) { Guild guild = event.getGuild(); List selectedRoles = event.getSelectedOptions() .stream() @@ -223,8 +222,8 @@ public void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, handleRoleSelection(event, guild, selectedRoles); } - private static void handleRoleSelection(@NotNull SelectMenuInteractionEvent event, - @NotNull Guild guild, @NotNull Collection selectedRoles) { + private static void handleRoleSelection(SelectMenuInteractionEvent event, Guild guild, + Collection selectedRoles) { Collection rolesToAdd = new ArrayList<>(selectedRoles.size()); Collection rolesToRemove = new ArrayList<>(selectedRoles.size()); @@ -244,8 +243,8 @@ private static void handleRoleSelection(@NotNull SelectMenuInteractionEvent even modifyRoles(event, event.getMember(), guild, rolesToAdd, rolesToRemove); } - @NotNull - private static Function> optionToRole(@NotNull Guild guild) { + @Nonnull + private static Function> optionToRole(Guild guild) { return option -> { Role role = guild.getRoleById(option.getValue()); @@ -259,16 +258,15 @@ private static Function> optionToRole(@NotNull Guil }; } - private static void modifyRoles(@NotNull IReplyCallback event, @NotNull Member target, - @NotNull Guild guild, @NotNull Collection rolesToAdd, - @NotNull Collection rolesToRemove) { + private static void modifyRoles(IReplyCallback event, Member target, Guild guild, + Collection rolesToAdd, Collection rolesToRemove) { guild.modifyMemberRoles(target, rolesToAdd, rolesToRemove) .flatMap(empty -> event.reply("Your roles have been updated.").setEphemeral(true)) .queue(); } - private static @NotNull MessageEmbed createEmbed(@NotNull String title, - @NotNull CharSequence description) { + @Nonnull + private static MessageEmbed createEmbed(String title, CharSequence description) { return new EmbedBuilder().setTitle(title) .setDescription(description) .setColor(AMBIENT_COLOR) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/basic/SuggestionsUpDownVoter.java b/application/src/main/java/org/togetherjava/tjbot/commands/basic/SuggestionsUpDownVoter.java index 280f32599e..84bd30ece1 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/basic/SuggestionsUpDownVoter.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/basic/SuggestionsUpDownVoter.java @@ -6,13 +6,13 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.exceptions.ErrorResponseException; import net.dv8tion.jda.api.requests.ErrorResponse; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.config.SuggestionsConfig; +import javax.annotation.Nonnull; import java.util.Optional; import java.util.regex.Pattern; @@ -33,14 +33,14 @@ public final class SuggestionsUpDownVoter extends MessageReceiverAdapter { * * @param config the config to use for this */ - public SuggestionsUpDownVoter(@NotNull Config config) { + public SuggestionsUpDownVoter(Config config) { super(Pattern.compile(config.getSuggestions().getChannelPattern())); this.config = config.getSuggestions(); } @Override - public void onMessageReceived(@NotNull MessageReceivedEvent event) { + public void onMessageReceived(MessageReceivedEvent event) { if (event.getAuthor().isBot() || event.isWebhookMessage() || !event.isFromGuild()) { return; } @@ -53,7 +53,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { reactWith(config.getDownVoteEmoteName(), FALLBACK_DOWN_VOTE, guild, message); } - private static void createThread(@NotNull Message message) { + private static void createThread(Message message) { String title = message.getContentRaw(); if (title.length() >= TITLE_MAX_LENGTH) { @@ -69,8 +69,8 @@ private static void createThread(@NotNull Message message) { message.createThreadChannel(title).queue(); } - private static void reactWith(@NotNull String emoteName, @NotNull String fallbackUnicodeEmote, - @NotNull Guild guild, @NotNull Message message) { + private static void reactWith(String emoteName, String fallbackUnicodeEmote, Guild guild, + Message message) { getEmoteByName(emoteName, guild).map(message::addReaction).orElseGet(() -> { logger.warn( "Unable to vote on a suggestion with the configured emote ('{}'), using fallback instead.", @@ -89,8 +89,8 @@ private static void reactWith(@NotNull String emoteName, @NotNull String fallbac }); } - private static @NotNull Optional getEmoteByName(@NotNull String name, - @NotNull Guild guild) { + @Nonnull + private static Optional getEmoteByName(String name, Guild guild) { return guild.getEmotesByName(name, false).stream().findAny(); } } 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 7e6899684f..6339bac007 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 @@ -13,13 +13,13 @@ import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.List; import java.util.Map; import java.util.Objects; @@ -144,7 +144,7 @@ public VcActivityCommand() { @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { Member member = Objects.requireNonNull(event.getMember(), "member is null"); GuildVoiceState voiceState = Objects.requireNonNull(member.getVoiceState(), "Voicestates aren't being cached, check the JDABuilder"); @@ -191,9 +191,8 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { handleSubcommand(event, voiceChannel, applicationId, maxUses, maxAgeDays, applicationName); } - - private static @NotNull Optional getKeyByValue(@NotNull Map map, - @NotNull V value) { + @Nonnull + private static Optional getKeyByValue(Map map, V value) { for (Map.Entry entry : map.entrySet()) { if (value.equals(entry.getKey())) { return Optional.of(entry.getKey()); @@ -203,10 +202,9 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { return Optional.empty(); } - private static void handleSubcommand(@NotNull SlashCommandInteractionEvent event, - @NotNull VoiceChannel voiceChannel, @NotNull String applicationId, - @Nullable Integer maxUses, @Nullable Integer maxAgeDays, - @NotNull String applicationName) { + private static void handleSubcommand(SlashCommandInteractionEvent event, + VoiceChannel voiceChannel, String applicationId, @Nullable Integer maxUses, + @Nullable Integer maxAgeDays, String applicationName) { voiceChannel.createInvite() @@ -219,9 +217,9 @@ private static void handleSubcommand(@NotNull SlashCommandInteractionEvent event } - private static @NotNull ReplyCallbackAction replyInvite( - @NotNull SlashCommandInteractionEvent event, @NotNull Invite invite, - @NotNull String applicationName) { + @Nonnull + private static ReplyCallbackAction replyInvite(SlashCommandInteractionEvent event, + Invite invite, String applicationName) { return event.reply(""" %s wants to start %s. Feel free to join by clicking %s , enjoy! @@ -229,7 +227,7 @@ private static void handleSubcommand(@NotNull SlashCommandInteractionEvent event """.formatted(event.getUser().getAsTag(), applicationName, invite.getUrl())); } - private static void handleErrors(@NotNull SlashCommandInteractionEvent event, + private static void handleErrors(SlashCommandInteractionEvent event, @Nullable Throwable throwable) { event.reply("Something went wrong :/").queue(); logger.warn("Something went wrong in the VcActivityCommand", throwable); @@ -242,7 +240,8 @@ private static void handleErrors(@NotNull SlashCommandInteractionEvent event, * @return the extracted integer if present, null otherwise **/ @Contract("null -> null") - private static @Nullable Integer requireIntOptionIfPresent(@Nullable OptionMapping option) { + @Nullable + private static Integer requireIntOptionIfPresent(@Nullable OptionMapping option) { return option == null ? null : Math.toIntExact(option.getAsLong()); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/basic/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/basic/package-info.java index 3394e9bcb5..177ae9c4c3 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/basic/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/basic/package-info.java @@ -2,4 +2,7 @@ * This package offers some basic commands that act as example for how to use the command system of * the application. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.basic; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentId.java b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentId.java index c5205e258b..5e297c7576 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentId.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentId.java @@ -1,6 +1,5 @@ package org.togetherjava.tjbot.commands.componentids; -import org.jetbrains.annotations.NotNull; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import java.util.List; @@ -14,5 +13,5 @@ * this component ID, when triggered * @param elements the additional elements to carry along this component ID, empty if not desired */ -public record ComponentId(@NotNull String userInteractorName, @NotNull List elements) { +public record ComponentId(String userInteractorName, List elements) { } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdGenerator.java b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdGenerator.java index 7514983890..91cd7a3228 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdGenerator.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdGenerator.java @@ -3,12 +3,11 @@ import net.dv8tion.jda.api.entities.Emoji; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.components.ComponentInteraction; -import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import net.dv8tion.jda.api.interactions.components.buttons.Button; - +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import org.togetherjava.tjbot.commands.SlashCommand; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; /** * Provides component ID generation. @@ -38,6 +37,6 @@ public interface ComponentIdGenerator { * @throws InvalidComponentIdFormatException if the given component ID was in an unexpected * format and could not be serialized */ - @NotNull - String generate(@NotNull ComponentId componentId, @NotNull Lifespan lifespan); + @Nonnull + String generate(ComponentId componentId, Lifespan lifespan); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdParser.java b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdParser.java index 5dbfcc4374..6d5071c787 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdParser.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdParser.java @@ -1,13 +1,12 @@ package org.togetherjava.tjbot.commands.componentids; import net.dv8tion.jda.api.entities.Emoji; -import net.dv8tion.jda.api.interactions.components.ComponentInteraction; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; +import net.dv8tion.jda.api.interactions.components.ComponentInteraction; import net.dv8tion.jda.api.interactions.components.buttons.Button; +import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; -import org.jetbrains.annotations.NotNull; - +import javax.annotation.Nonnull; import java.util.Optional; /** @@ -39,6 +38,6 @@ public interface ComponentIdParser { * @throws InvalidComponentIdFormatException if the component ID associated to the given UUID * was in an unexpected format and could not be deserialized */ - @NotNull - Optional parse(@NotNull String uuid); + @Nonnull + Optional parse(String uuid); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdStore.java b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdStore.java index 7f93b79961..882505d8ba 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdStore.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/ComponentIdStore.java @@ -5,15 +5,15 @@ import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import org.togetherjava.tjbot.commands.SlashCommand; -import org.jetbrains.annotations.NotNull; import org.jooq.Result; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.togetherjava.tjbot.commands.SlashCommand; import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.db.generated.tables.ComponentIds; import org.togetherjava.tjbot.db.generated.tables.records.ComponentIdsRecord; +import javax.annotation.Nonnull; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalUnit; @@ -84,7 +84,7 @@ public final class ComponentIdStore implements AutoCloseable { * * @param database the database to use to persist component IDs in */ - public ComponentIdStore(@NotNull Database database) { + public ComponentIdStore(Database database) { this(database, EVICT_DATABASE_EVERY_INITIAL_DELAY, EVICT_DATABASE_EVERY_DELAY, EVICT_DATABASE_EVERY_UNIT, EVICT_DATABASE_OLDER_THAN, EVICT_DATABASE_OLDER_THAN_UNIT); @@ -103,9 +103,8 @@ public ComponentIdStore(@NotNull Database database) { * @param evictOlderThanUnit the unit of the 'evictOlderThan' value */ @SuppressWarnings({"WeakerAccess", "ConstructorWithTooManyParameters"}) - public ComponentIdStore(@NotNull Database database, long evictEveryInitialDelay, - long evictEveryDelay, ChronoUnit evictEveryUnit, long evictOlderThan, - @SuppressWarnings("TypeMayBeWeakened") ChronoUnit evictOlderThanUnit) { + public ComponentIdStore(Database database, long evictEveryInitialDelay, long evictEveryDelay, + ChronoUnit evictEveryUnit, long evictOlderThan, ChronoUnit evictOlderThanUnit) { this.database = database; evictDatabaseOlderThan = evictOlderThan; evictDatabaseOlderThanUnit = evictOlderThanUnit; @@ -137,7 +136,7 @@ public ComponentIdStore(@NotNull Database database, long evictEveryInitialDelay, * * @param listener the listener to add */ - public void addComponentIdRemovedListener(@NotNull Consumer listener) { + public void addComponentIdRemovedListener(Consumer listener) { componentIdRemovedListeners.add(listener); } @@ -156,7 +155,8 @@ public void addComponentIdRemovedListener(@NotNull Consumer listene * format and could not be serialized */ @SuppressWarnings("WeakerAccess") - public @NotNull Optional get(@NotNull UUID uuid) { + @Nonnull + public Optional get(UUID uuid) { synchronized (storeLock) { // Get it from the cache or, if not found, the database return Optional.ofNullable(storeCache.getIfPresent(uuid)).or(() -> { @@ -188,8 +188,7 @@ public void addComponentIdRemovedListener(@NotNull Consumer listene * was in an unexpected format and could not be deserialized */ @SuppressWarnings("WeakerAccess") - public void putOrThrow(@NotNull UUID uuid, @NotNull ComponentId componentId, - @NotNull Lifespan lifespan) { + public void putOrThrow(UUID uuid, ComponentId componentId, Lifespan lifespan) { Supplier alreadyExistsMessageSupplier = () -> "The UUID '%s' already exists and is associated to a component id." .formatted(uuid); @@ -218,7 +217,8 @@ public void putOrThrow(@NotNull UUID uuid, @NotNull ComponentId componentId, } } - private @NotNull Optional getFromDatabase(@NotNull UUID uuid) { + @Nonnull + private Optional getFromDatabase(UUID uuid) { return database.read(context -> Optional .ofNullable(context.selectFrom(ComponentIds.COMPONENT_IDS) .where(ComponentIds.COMPONENT_IDS.UUID.eq(uuid.toString())) @@ -235,7 +235,7 @@ public void putOrThrow(@NotNull UUID uuid, @NotNull ComponentId componentId, * @param uuid the uuid to heat * @throws IllegalArgumentException if there is no, or multiple, records associated to that UUID */ - private void heatRecord(@NotNull UUID uuid) { + private void heatRecord(UUID uuid) { int updatedRecords; synchronized (storeLock) { updatedRecords = @@ -294,7 +294,8 @@ private void evictDatabase() { } } - private static @NotNull String serializeComponentId(@NotNull ComponentId componentId) { + @Nonnull + private static String serializeComponentId(ComponentId componentId) { try { return CSV.writerFor(ComponentId.class) .with(CSV.schemaFor(ComponentId.class)) @@ -304,7 +305,8 @@ private void evictDatabase() { } } - private static @NotNull ComponentId deserializeComponentId(@NotNull String componentId) { + @Nonnull + private static ComponentId deserializeComponentId(String componentId) { try { return CSV.readerFor(ComponentId.class) .with(CSV.schemaFor(ComponentId.class)) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/package-info.java index 239d79060a..e52a9953c4 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/componentids/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/componentids/package-info.java @@ -2,7 +2,7 @@ * This package provides utilities to generate, persist and parse component IDs. *

* See - * {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(net.dv8tion.jda.api.events.interaction.SlashCommandInteractionEvent)} + * {@link org.togetherjava.tjbot.commands.SlashCommand#onSlashCommand(net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent)} * for details on component IDs. *

* The class {@link org.togetherjava.tjbot.commands.componentids.ComponentIdStore} is the central @@ -10,4 +10,7 @@ * {@link org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator} and * {@link org.togetherjava.tjbot.commands.componentids.ComponentIdParser}. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.componentids; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java index 8aa38da231..2267fe851d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/FileSharingMessageListener.java @@ -8,12 +8,12 @@ import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.interactions.components.buttons.Button; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; import java.io.IOException; import java.io.InputStream; import java.io.UncheckedIOException; @@ -23,7 +23,10 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; @@ -55,7 +58,7 @@ public class FileSharingMessageListener extends MessageReceiverAdapter { * @param config used to get api key and channel names. * @see org.togetherjava.tjbot.commands.Features */ - public FileSharingMessageListener(@NotNull Config config) { + public FileSharingMessageListener(Config config) { super(Pattern.compile(".*")); gistApiKey = config.getGistApiKey(); @@ -66,7 +69,7 @@ public FileSharingMessageListener(@NotNull Config config) { } @Override - public void onMessageReceived(@NotNull MessageReceivedEvent event) { + public void onMessageReceived(MessageReceivedEvent event) { User author = event.getAuthor(); if (author.isBot() || event.isWebhookMessage()) { return; @@ -98,7 +101,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { }); } - private boolean isAttachmentRelevant(@NotNull Message.Attachment attachment) { + private boolean isAttachmentRelevant(Message.Attachment attachment) { String extension = attachment.getFileExtension(); if (extension == null) { return false; @@ -107,8 +110,8 @@ private boolean isAttachmentRelevant(@NotNull Message.Attachment attachment) { } - private void processAttachments(@NotNull MessageReceivedEvent event, - @NotNull List attachments) { + private void processAttachments(MessageReceivedEvent event, + List attachments) { Map nameToFile = new ConcurrentHashMap<>(); @@ -130,7 +133,8 @@ private void processAttachments(@NotNull MessageReceivedEvent event, sendResponse(event, url); } - private @NotNull String readAttachment(@NotNull InputStream stream) { + @Nonnull + private String readAttachment(InputStream stream) { try (stream) { return new String(stream.readAllBytes(), StandardCharsets.UTF_8); } catch (IOException e) { @@ -138,7 +142,8 @@ private void processAttachments(@NotNull MessageReceivedEvent event, } } - private @NotNull String getNameOf(@NotNull Message.Attachment attachment) { + @Nonnull + private String getNameOf(Message.Attachment attachment) { String fileName = attachment.getFileName(); String fileExtension = attachment.getFileExtension(); @@ -158,7 +163,8 @@ private void processAttachments(@NotNull MessageReceivedEvent event, return fileName; } - private @NotNull String uploadToGist(@NotNull GistRequest jsonRequest) { + @Nonnull + private String uploadToGist(GistRequest jsonRequest) { String body; try { body = JSON.writeValueAsString(jsonRequest); @@ -204,7 +210,7 @@ private void processAttachments(@NotNull MessageReceivedEvent event, return gistResponse.getHtmlUrl(); } - private void sendResponse(@NotNull MessageReceivedEvent event, @NotNull String url) { + private void sendResponse(MessageReceivedEvent event, String url) { Message message = event.getMessage(); String messageContent = "I uploaded your attachments as **gist**. That way, they are easier to read for everyone, especially mobile users 👍"; @@ -212,7 +218,7 @@ private void sendResponse(@NotNull MessageReceivedEvent event, @NotNull String u message.reply(messageContent).setActionRow(Button.link(url, "gist")).queue(); } - private boolean isHelpThread(@NotNull MessageReceivedEvent event) { + private boolean isHelpThread(MessageReceivedEvent event) { if (event.getChannelType() != ChannelType.GUILD_PUBLIC_THREAD) { return false; } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java index cba4472b4e..343a7a1730 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFile.java @@ -1,10 +1,8 @@ package org.togetherjava.tjbot.commands.filesharing; -import org.jetbrains.annotations.NotNull; - /** * @see Create a Gist via * API */ -record GistFile(@NotNull String content) { +record GistFile(String content) { } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java index 3d3f8ca032..1541a676c7 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistFiles.java @@ -1,7 +1,6 @@ package org.togetherjava.tjbot.commands.filesharing; import com.fasterxml.jackson.annotation.JsonAnyGetter; -import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -9,5 +8,5 @@ * @see Create a Gist via * API */ -record GistFiles(@NotNull @JsonAnyGetter Map nameToContent) { +record GistFiles(@JsonAnyGetter Map nameToContent) { } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java index d1e1156547..6b1dd78575 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistRequest.java @@ -1,12 +1,10 @@ package org.togetherjava.tjbot.commands.filesharing; import com.fasterxml.jackson.annotation.JsonProperty; -import org.jetbrains.annotations.NotNull; /** * @see Create a Gist via * API */ -record GistRequest(@NotNull String description, @JsonProperty("public") boolean isPublic, - @NotNull GistFiles files) { +record GistRequest(String description, @JsonProperty("public") boolean isPublic, GistFiles files) { } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java index af7d3f2ddf..1d35277fcb 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/GistResponse.java @@ -2,7 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nonnull; /** * @see Create a Gist via @@ -13,11 +14,12 @@ final class GistResponse { @JsonProperty("html_url") private String htmlUrl; - public @NotNull String getHtmlUrl() { - return this.htmlUrl; + @Nonnull + public String getHtmlUrl() { + return htmlUrl; } - public void setHtmlUrl(@NotNull String htmlUrl) { + public void setHtmlUrl(String htmlUrl) { this.htmlUrl = htmlUrl; } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java index 3eba1af69d..8f5f6befeb 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/filesharing/package-info.java @@ -2,4 +2,7 @@ * This package offers all the functionality for automatically uploading files to sharing services. * The core class is {@link org.togetherjava.tjbot.commands.filesharing.FileSharingMessageListener}. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.filesharing; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/AskCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/AskCommand.java index 70160c207b..16968d2d9b 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/AskCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/AskCommand.java @@ -9,13 +9,13 @@ import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.requests.ErrorResponse; import net.dv8tion.jda.api.requests.RestAction; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; import java.util.Optional; import static org.togetherjava.tjbot.commands.help.HelpSystemHelper.TITLE_COMPACT_LENGTH_MAX; @@ -54,7 +54,7 @@ public final class AskCommand extends SlashCommandAdapter { * @param config the config to use * @param helper the helper to use */ - public AskCommand(@NotNull Config config, @NotNull HelpSystemHelper helper) { + public AskCommand(Config config, HelpSystemHelper helper) { super("ask", "Ask a question - use this in the staging channel", SlashCommandVisibility.GUILD); @@ -72,7 +72,7 @@ public AskCommand(@NotNull Config config, @NotNull HelpSystemHelper helper) { } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { String title = event.getOption(TITLE_OPTION).getAsString(); String category = event.getOption(CATEGORY_OPTION).getAsString(); @@ -102,7 +102,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { }, e -> handleFailure(e, eventHook)); } - private boolean handleIsValidTitle(@NotNull CharSequence title, @NotNull IReplyCallback event) { + private boolean handleIsValidTitle(CharSequence title, IReplyCallback event) { if (HelpSystemHelper.isTitleValid(title)) { return true; } @@ -119,18 +119,18 @@ private boolean handleIsValidTitle(@NotNull CharSequence title, @NotNull IReplyC return false; } - private @NotNull RestAction handleEvent(@NotNull InteractionHook eventHook, - @NotNull ThreadChannel threadChannel, @NotNull Member author, @NotNull String title, - @NotNull String category, @NotNull Guild guild) { + @Nonnull + private RestAction handleEvent(InteractionHook eventHook, ThreadChannel threadChannel, + Member author, String title, String category, Guild guild) { helper.writeHelpThreadToDatabase(author, threadChannel); return sendInitialMessage(guild, threadChannel, author, title, category) .flatMap(any -> notifyUser(eventHook, threadChannel)) .flatMap(any -> helper.sendExplanationMessage(threadChannel)); } - private RestAction sendInitialMessage(@NotNull Guild guild, - @NotNull ThreadChannel threadChannel, @NotNull Member author, @NotNull String title, - @NotNull String category) { + @Nonnull + private RestAction sendInitialMessage(Guild guild, ThreadChannel threadChannel, + Member author, String title, String category) { String roleMentionDescription = helper.handleFindRoleForCategory(category, guild) .map(role -> " (%s)".formatted(role.getAsMention())) .orElse(""); @@ -148,15 +148,15 @@ private RestAction sendInitialMessage(@NotNull Guild guild, .flatMap(message -> message.editMessage(contentWithRole)); } - private static @NotNull RestAction notifyUser(@NotNull InteractionHook eventHook, - @NotNull IMentionable threadChannel) { + @Nonnull + private static RestAction notifyUser(InteractionHook eventHook, + IMentionable threadChannel) { return eventHook.editOriginal(""" Created a thread for you: %s Please ask your question there, thanks.""".formatted(threadChannel.getAsMention())); } - private static void handleFailure(@NotNull Throwable exception, - @NotNull InteractionHook eventHook) { + private static void handleFailure(Throwable exception, InteractionHook eventHook) { if (exception instanceof ErrorResponseException responseException) { ErrorResponse response = responseException.getErrorResponse(); if (response == ErrorResponse.MAX_CHANNELS diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/AutoPruneHelperRoutine.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/AutoPruneHelperRoutine.java index f633972da8..bef93f9889 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/AutoPruneHelperRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/AutoPruneHelperRoutine.java @@ -5,7 +5,6 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.TextChannel; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.Routine; @@ -13,6 +12,7 @@ import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.moderation.ModAuditLogWriter; +import javax.annotation.Nonnull; import java.time.Duration; import java.time.Instant; import java.time.Period; @@ -50,8 +50,8 @@ public final class AutoPruneHelperRoutine implements Routine { * @param modAuditLogWriter to inform mods when manual pruning becomes necessary * @param database to determine whether an user is inactive */ - public AutoPruneHelperRoutine(@NotNull Config config, @NotNull HelpSystemHelper helper, - @NotNull ModAuditLogWriter modAuditLogWriter, @NotNull Database database) { + public AutoPruneHelperRoutine(Config config, HelpSystemHelper helper, + ModAuditLogWriter modAuditLogWriter, Database database) { allCategories = config.getHelpSystem().getCategories(); this.helper = helper; this.modAuditLogWriter = modAuditLogWriter; @@ -59,16 +59,17 @@ public AutoPruneHelperRoutine(@NotNull Config config, @NotNull HelpSystemHelper } @Override - public @NotNull Schedule createSchedule() { + @Nonnull + public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, 1, TimeUnit.HOURS); } @Override - public void runRoutine(@NotNull JDA jda) { + public void runRoutine(JDA jda) { jda.getGuildCache().forEach(this::pruneForGuild); } - private void pruneForGuild(@NotNull Guild guild) { + private void pruneForGuild(Guild guild) { TextChannel overviewChannel = guild.getTextChannels() .stream() .filter(channel -> helper.isOverviewChannelName(channel.getName())) @@ -83,8 +84,7 @@ private void pruneForGuild(@NotNull Guild guild) { .forEach(role -> pruneRoleIfFull(role, overviewChannel, now)); } - private void pruneRoleIfFull(@NotNull Role role, @NotNull TextChannel overviewChannel, - @NotNull Instant when) { + private void pruneRoleIfFull(Role role, TextChannel overviewChannel, Instant when) { role.getGuild().findMembersWithRoles(role).onSuccess(members -> { if (isRoleFull(members)) { logger.debug("Helper role {} is full, starting to prune.", role.getName()); @@ -93,12 +93,12 @@ private void pruneRoleIfFull(@NotNull Role role, @NotNull TextChannel overviewCh }); } - private boolean isRoleFull(@NotNull Collection members) { + private boolean isRoleFull(Collection members) { return members.size() >= ROLE_FULL_THRESHOLD; } - private void pruneRole(@NotNull Role role, @NotNull List members, - @NotNull TextChannel overviewChannel, @NotNull Instant when) { + private void pruneRole(Role role, List members, TextChannel overviewChannel, + Instant when) { List membersShuffled = new ArrayList<>(members); Collections.shuffle(membersShuffled); @@ -124,7 +124,7 @@ private void pruneRole(@NotNull Role role, @NotNull List membe membersToPrune.forEach(member -> pruneMemberFromRole(member, role, overviewChannel)); } - private boolean isMemberInactive(@NotNull Member member, @NotNull Instant when) { + private boolean isMemberInactive(Member member, Instant when) { if (member.hasTimeJoined()) { Instant memberJoined = member.getTimeJoined().toInstant(); if (Duration.between(memberJoined, when).toDays() <= RECENTLY_JOINED_DAYS) { @@ -143,8 +143,7 @@ private boolean isMemberInactive(@NotNull Member member, @NotNull Instant when) .and(HELP_CHANNEL_MESSAGES.SENT_AT.greaterThan(latestActiveMoment)))) == 0; } - private void pruneMemberFromRole(@NotNull Member member, @NotNull Role role, - @NotNull TextChannel overviewChannel) { + private void pruneMemberFromRole(Member member, Role role, TextChannel overviewChannel) { Guild guild = member.getGuild(); String dmMessage = @@ -160,7 +159,7 @@ private void pruneMemberFromRole(@NotNull Member member, @NotNull Role role, .queue(); } - private void warnModsAbout(@NotNull String message, @NotNull Guild guild) { + private void warnModsAbout(String message, Guild guild) { logger.warn(message); modAuditLogWriter.write("Auto-prune helpers", message, null, Instant.now(), guild); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/BotMessageCleanup.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/BotMessageCleanup.java index 8584b29430..f066380f27 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/BotMessageCleanup.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/BotMessageCleanup.java @@ -7,13 +7,13 @@ import net.dv8tion.jda.api.entities.TextChannel; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.internal.requests.CompletedRestAction; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.Routine; import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.config.HelpSystemConfig; +import javax.annotation.Nonnull; import java.time.Duration; import java.time.Instant; import java.time.OffsetDateTime; @@ -46,7 +46,7 @@ public final class BotMessageCleanup implements Routine { * * @param config the config to use */ - public BotMessageCleanup(@NotNull Config config) { + public BotMessageCleanup(Config config) { this.config = config.getHelpSystem(); isStagingChannelName = Pattern.compile(config.getHelpSystem().getStagingChannelPattern()) @@ -54,16 +54,17 @@ public BotMessageCleanup(@NotNull Config config) { } @Override - public @NotNull Schedule createSchedule() { + @Nonnull + public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 1, 1, TimeUnit.MINUTES); } @Override - public void runRoutine(@NotNull JDA jda) { + public void runRoutine(JDA jda) { jda.getGuildCache().forEach(this::cleanupBotMessagesForGuild); } - private void cleanupBotMessagesForGuild(@NotNull Guild guild) { + private void cleanupBotMessagesForGuild(Guild guild) { Optional maybeStagingChannel = handleRequireStagingChannel(guild); if (maybeStagingChannel.isEmpty()) { @@ -78,7 +79,8 @@ private void cleanupBotMessagesForGuild(@NotNull Guild guild) { .queue(); } - private @NotNull Optional handleRequireStagingChannel(@NotNull Guild guild) { + @Nonnull + private Optional handleRequireStagingChannel(Guild guild) { Optional maybeChannel = guild.getTextChannelCache() .stream() .filter(channel -> isStagingChannelName.test(channel.getName())) @@ -94,7 +96,7 @@ private void cleanupBotMessagesForGuild(@NotNull Guild guild) { return maybeChannel; } - private static boolean shouldMessageBeCleanedUp(@NotNull Message message) { + private static boolean shouldMessageBeCleanedUp(Message message) { if (!message.getAuthor().isBot()) { return false; } @@ -106,8 +108,9 @@ private static boolean shouldMessageBeCleanedUp(@NotNull Message message) { return deleteWhen.isBefore(Instant.now()); } - private static @NotNull RestAction cleanupBotMessages( - @NotNull GuildMessageChannel channel, @NotNull Collection messages) { + @Nonnull + private static RestAction cleanupBotMessages(GuildMessageChannel channel, + Collection messages) { logger.debug("Cleaning up old bot messages in the staging channel"); List messageIdsToDelete = messages.stream() .filter(BotMessageCleanup::shouldMessageBeCleanedUp) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/ChangeHelpCategoryCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/ChangeHelpCategoryCommand.java index 9bf24e54f0..1f84add910 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/ChangeHelpCategoryCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/ChangeHelpCategoryCommand.java @@ -11,11 +11,11 @@ import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.requests.RestAction; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Locale; @@ -47,7 +47,7 @@ public final class ChangeHelpCategoryCommand extends SlashCommandAdapter { * @param config the config to use * @param helper the helper to use */ - public ChangeHelpCategoryCommand(@NotNull Config config, @NotNull HelpSystemHelper helper) { + public ChangeHelpCategoryCommand(Config config, HelpSystemHelper helper) { super("change-help-category", "changes the category of a help thread", SlashCommandVisibility.GUILD); @@ -68,7 +68,7 @@ public ChangeHelpCategoryCommand(@NotNull Config config, @NotNull HelpSystemHelp } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { String category = event.getOption(CATEGORY_OPTION).getAsString(); ThreadChannel helpThread = event.getThreadChannel(); @@ -96,9 +96,9 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { .queue(); } - private @NotNull RestAction sendCategoryChangedMessage(@NotNull Guild guild, - @NotNull InteractionHook hook, @NotNull ThreadChannel helpThread, - @NotNull String category) { + @Nonnull + private RestAction sendCategoryChangedMessage(Guild guild, InteractionHook hook, + ThreadChannel helpThread, String category) { String changedContent = "Changed the category to **%s**.".formatted(category); var action = hook.editOriginal(changedContent); @@ -119,7 +119,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { .flatMap(message -> message.editMessage(headsUpWithRole))); } - private boolean isHelpThreadOnCooldown(@NotNull ThreadChannel helpThread) { + private boolean isHelpThreadOnCooldown(ThreadChannel helpThread) { return Optional .ofNullable(helpThreadIdToLastCategoryChange.getIfPresent(helpThread.getIdLong())) .map(lastCategoryChange -> lastCategoryChange.plus(COOLDOWN_DURATION_VALUE, diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/ChangeHelpTitleCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/ChangeHelpTitleCommand.java index 5090f26d07..8ea5288f25 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/ChangeHelpTitleCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/ChangeHelpTitleCommand.java @@ -6,7 +6,6 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; import net.dv8tion.jda.api.interactions.commands.OptionType; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; @@ -40,7 +39,7 @@ public final class ChangeHelpTitleCommand extends SlashCommandAdapter { * * @param helper the helper to use */ - public ChangeHelpTitleCommand(@NotNull HelpSystemHelper helper) { + public ChangeHelpTitleCommand(HelpSystemHelper helper) { super("change-help-title", "changes the title of a help thread", SlashCommandVisibility.GUILD); @@ -55,7 +54,7 @@ public ChangeHelpTitleCommand(@NotNull HelpSystemHelper helper) { } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { String title = event.getOption(TITLE_OPTION).getAsString(); if (!handleIsValidTitle(title, event)) { @@ -84,7 +83,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { .queue(); } - private boolean isHelpThreadOnCooldown(@NotNull ThreadChannel helpThread) { + private boolean isHelpThreadOnCooldown(ThreadChannel helpThread) { return Optional .ofNullable(helpThreadIdToLastTitleChange.getIfPresent(helpThread.getIdLong())) .map(lastCategoryChange -> lastCategoryChange.plus(COOLDOWN_DURATION_VALUE, @@ -93,7 +92,7 @@ private boolean isHelpThreadOnCooldown(@NotNull ThreadChannel helpThread) { .isPresent(); } - private boolean handleIsValidTitle(@NotNull CharSequence title, @NotNull IReplyCallback event) { + private boolean handleIsValidTitle(CharSequence title, IReplyCallback event) { if (HelpSystemHelper.isTitleValid(title)) { return true; } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/CloseCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/CloseCommand.java index 437e75131c..3b0e348e7e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/CloseCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/CloseCommand.java @@ -6,7 +6,6 @@ import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.entities.ThreadChannel; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; @@ -41,7 +40,7 @@ public CloseCommand() { } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { ThreadChannel helpThread = event.getThreadChannel(); if (helpThread.isArchived()) { event.reply("This thread is already closed.").setEphemeral(true).queue(); @@ -66,7 +65,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { event.replyEmbeds(embed).flatMap(any -> helpThread.getManager().setArchived(true)).queue(); } - private boolean isHelpThreadOnCooldown(@NotNull ThreadChannel helpThread) { + private boolean isHelpThreadOnCooldown(ThreadChannel helpThread) { return Optional.ofNullable(helpThreadIdToLastClose.getIfPresent(helpThread.getIdLong())) .map(lastCategoryChange -> lastCategoryChange.plus(COOLDOWN_DURATION_VALUE, COOLDOWN_DURATION_UNIT)) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpSystemHelper.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpSystemHelper.java index b30c1a56d9..e8500af163 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpSystemHelper.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpSystemHelper.java @@ -5,8 +5,6 @@ import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.MessageAction; import net.dv8tion.jda.internal.requests.CompletedRestAction; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.config.Config; @@ -15,6 +13,8 @@ import org.togetherjava.tjbot.db.generated.tables.HelpThreads; import org.togetherjava.tjbot.db.generated.tables.records.HelpThreadsRecord; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.awt.Color; import java.io.InputStream; import java.util.List; @@ -60,7 +60,7 @@ public final class HelpSystemHelper { * @param config the config to use * @param database the database to store help thread metadata in */ - public HelpSystemHelper(@NotNull Config config, @NotNull Database database) { + public HelpSystemHelper(Config config, Database database) { HelpSystemConfig helpConfig = config.getHelpSystem(); this.database = database; @@ -73,7 +73,8 @@ public HelpSystemHelper(@NotNull Config config, @NotNull Database database) { categoryRoleSuffix = helpConfig.getCategoryRoleSuffix(); } - RestAction sendExplanationMessage(@NotNull MessageChannel threadChannel) { + @Nonnull + RestAction sendExplanationMessage(MessageChannel threadChannel) { boolean useCodeSyntaxExampleImage = true; InputStream codeSyntaxExampleData = AskCommand.class.getResourceAsStream("/" + CODE_SYNTAX_EXAMPLE_PATH); @@ -119,20 +120,21 @@ void writeHelpThreadToDatabase(Member author, ThreadChannel threadChannel) { }); } - private static @NotNull MessageEmbed embedWith(@NotNull CharSequence message) { + @Nonnull + private static MessageEmbed embedWith(CharSequence message) { return embedWith(message, null); } - private static @NotNull MessageEmbed embedWith(@NotNull CharSequence message, - @Nullable String imageUrl) { + @Nonnull + private static MessageEmbed embedWith(CharSequence message, @Nullable String imageUrl) { return new EmbedBuilder().setColor(AMBIENT_COLOR) .setDescription(message) .setImage(imageUrl) .build(); } - @NotNull - Optional handleFindRoleForCategory(@NotNull String category, @NotNull Guild guild) { + @Nonnull + Optional handleFindRoleForCategory(String category, Guild guild) { String roleName = category + categoryRoleSuffix; Optional maybeHelperRole = guild.getRolesByName(roleName, true).stream().findAny(); @@ -143,14 +145,13 @@ Optional handleFindRoleForCategory(@NotNull String category, @NotNull Guil return maybeHelperRole; } - @NotNull - Optional getCategoryOfChannel(@NotNull Channel channel) { + @Nonnull + Optional getCategoryOfChannel(Channel channel) { return Optional.ofNullable(HelpThreadName.ofChannelName(channel.getName()).category); } - @NotNull - RestAction renameChannelToCategory(@NotNull GuildChannel channel, - @NotNull String category) { + @Nonnull + RestAction renameChannelToCategory(GuildChannel channel, String category) { HelpThreadName currentName = HelpThreadName.ofChannelName(channel.getName()); HelpThreadName nextName = new HelpThreadName(currentName.activity, category, currentName.title); @@ -158,8 +159,8 @@ RestAction renameChannelToCategory(@NotNull GuildChannel channel, return renameChannel(channel, currentName, nextName); } - @NotNull - RestAction renameChannelToTitle(@NotNull GuildChannel channel, @NotNull String title) { + @Nonnull + RestAction renameChannelToTitle(GuildChannel channel, String title) { HelpThreadName currentName = HelpThreadName.ofChannelName(channel.getName()); HelpThreadName nextName = new HelpThreadName(currentName.activity, currentName.category, title); @@ -167,9 +168,8 @@ RestAction renameChannelToTitle(@NotNull GuildChannel channel, @NotNull St return renameChannel(channel, currentName, nextName); } - @NotNull - RestAction renameChannelToActivity(@NotNull GuildChannel channel, - @NotNull ThreadActivity activity) { + @Nonnull + RestAction renameChannelToActivity(GuildChannel channel, ThreadActivity activity) { HelpThreadName currentName = HelpThreadName.ofChannelName(channel.getName()); HelpThreadName nextName = new HelpThreadName(activity, currentName.category, currentName.title); @@ -177,9 +177,9 @@ RestAction renameChannelToActivity(@NotNull GuildChannel channel, return renameChannel(channel, currentName, nextName); } - @NotNull - private RestAction renameChannel(@NotNull GuildChannel channel, - @NotNull HelpThreadName currentName, @NotNull HelpThreadName nextName) { + @Nonnull + private RestAction renameChannel(GuildChannel channel, HelpThreadName currentName, + HelpThreadName nextName) { if (currentName.equals(nextName)) { // Do not stress rate limits if no actual change is done return new CompletedRestAction<>(channel.getJDA(), null); @@ -188,25 +188,25 @@ private RestAction renameChannel(@NotNull GuildChannel channel, return channel.getManager().setName(nextName.toChannelName()); } - boolean isOverviewChannelName(@NotNull String channelName) { + boolean isOverviewChannelName(String channelName) { return isOverviewChannelName.test(channelName); } - @NotNull + @Nonnull String getOverviewChannelPattern() { return overviewChannelPattern; } - boolean isStagingChannelName(@NotNull String channelName) { + boolean isStagingChannelName(String channelName) { return isStagingChannelName.test(channelName); } - @NotNull + @Nonnull String getStagingChannelPattern() { return stagingChannelPattern; } - static boolean isTitleValid(@NotNull CharSequence title) { + static boolean isTitleValid(CharSequence title) { String titleCompact = TITLE_COMPACT_REMOVAL_PATTERN.matcher(title).replaceAll(""); return titleCompact.length() >= TITLE_COMPACT_LENGTH_MIN @@ -214,9 +214,9 @@ static boolean isTitleValid(@NotNull CharSequence title) { && !titleCompact.toLowerCase(Locale.US).contains("help"); } - @NotNull - Optional handleRequireOverviewChannel(@NotNull Guild guild, - @NotNull Consumer consumeChannelPatternIfNotFound) { + @Nonnull + Optional handleRequireOverviewChannel(Guild guild, + Consumer consumeChannelPatternIfNotFound) { Predicate isChannelName = this::isOverviewChannelName; String channelPattern = getOverviewChannelPattern(); @@ -232,9 +232,9 @@ Optional handleRequireOverviewChannel(@NotNull Guild guild, return maybeChannel; } - @NotNull - Optional handleRequireOverviewChannelForAsk(@NotNull Guild guild, - @NotNull MessageChannel respondTo) { + @Nonnull + Optional handleRequireOverviewChannelForAsk(Guild guild, + MessageChannel respondTo) { return handleRequireOverviewChannel(guild, channelPattern -> { logger.warn( "Attempted to create a help thread, did not find the overview channel matching the configured pattern '{}' for guild '{}'", @@ -246,8 +246,8 @@ Optional handleRequireOverviewChannelForAsk(@NotNull Guild guild, }); } - @NotNull - List getActiveThreadsIn(@NotNull TextChannel channel) { + @Nonnull + List getActiveThreadsIn(TextChannel channel) { return channel.getThreadChannels() .stream() .filter(Predicate.not(ThreadChannel::isArchived)) @@ -255,8 +255,9 @@ List getActiveThreadsIn(@NotNull TextChannel channel) { } record HelpThreadName(@Nullable ThreadActivity activity, @Nullable String category, - @NotNull String title) { - static @NotNull HelpThreadName ofChannelName(@NotNull CharSequence channelName) { + String title) { + @Nonnull + static HelpThreadName ofChannelName(CharSequence channelName) { Matcher matcher = EXTRACT_HELP_NAME_PATTERN.matcher(channelName); if (!matcher.matches()) { @@ -273,7 +274,7 @@ record HelpThreadName(@Nullable ThreadActivity activity, @Nullable String catego return new HelpThreadName(activity, category, title); } - @NotNull + @Nonnull String toChannelName() { String activityText = activity == null ? "" : activity.getSymbol() + " "; String categoryText = category == null ? "" : "[%s] ".formatted(category); @@ -289,15 +290,17 @@ enum ThreadActivity { private final String symbol; - ThreadActivity(@NotNull String symbol) { + ThreadActivity(String symbol) { this.symbol = symbol; } - public @NotNull String getSymbol() { + @Nonnull + public String getSymbol() { return symbol; } - static @NotNull ThreadActivity ofSymbol(@NotNull String symbol) { + @Nonnull + static ThreadActivity ofSymbol(String symbol) { return Stream.of(values()) .filter(activity -> activity.getSymbol().equals(symbol)) .findAny() diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadActivityUpdater.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadActivityUpdater.java index f21cad798b..9cf9a42c30 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadActivityUpdater.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadActivityUpdater.java @@ -3,11 +3,11 @@ import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.requests.RestAction; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.Routine; +import javax.annotation.Nonnull; import java.util.List; import java.util.Map; import java.util.Optional; @@ -33,21 +33,22 @@ public final class HelpThreadActivityUpdater implements Routine { * * @param helper the helper to use */ - public HelpThreadActivityUpdater(@NotNull HelpSystemHelper helper) { + public HelpThreadActivityUpdater(HelpSystemHelper helper) { this.helper = helper; } @Override - public @NotNull Schedule createSchedule() { + @Nonnull + public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 1, SCHEDULE_MINUTES, TimeUnit.MINUTES); } @Override - public void runRoutine(@NotNull JDA jda) { + public void runRoutine(JDA jda) { jda.getGuildCache().forEach(this::updateActivityForGuild); } - private void updateActivityForGuild(@NotNull Guild guild) { + private void updateActivityForGuild(Guild guild) { Optional maybeOverviewChannel = helper .handleRequireOverviewChannel(guild, channelPattern -> logger.warn( "Unable to update help thread overview, did not find an overview channel matching the configured pattern '{}' for guild '{}'", @@ -66,14 +67,15 @@ private void updateActivityForGuild(@NotNull Guild guild) { activeThreads.forEach(this::updateActivityForThread); } - private void updateActivityForThread(@NotNull ThreadChannel threadChannel) { + private void updateActivityForThread(ThreadChannel threadChannel) { determineActivity(threadChannel) .flatMap( threadActivity -> helper.renameChannelToActivity(threadChannel, threadActivity)) .queue(); } - private static @NotNull RestAction determineActivity( + @Nonnull + private static RestAction determineActivity( MessageChannel channel) { return channel.getHistory().retrievePast(ACTIVITY_DETERMINE_MESSAGE_LIMIT).map(messages -> { if (messages.size() >= ACTIVITY_DETERMINE_MESSAGE_LIMIT) { @@ -94,7 +96,7 @@ private void updateActivityForThread(@NotNull ThreadChannel threadChannel) { }); } - private static boolean isBotMessage(@NotNull Message message) { + private static boolean isBotMessage(Message message) { return message.getAuthor().equals(message.getJDA().getSelfUser()); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadAutoArchiver.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadAutoArchiver.java index 00b093956c..b8f3689666 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadAutoArchiver.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadAutoArchiver.java @@ -4,11 +4,11 @@ import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.utils.TimeUtil; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.Routine; +import javax.annotation.Nonnull; import java.time.Duration; import java.time.Instant; import java.util.List; @@ -31,21 +31,22 @@ public final class HelpThreadAutoArchiver implements Routine { * * @param helper the helper to use */ - public HelpThreadAutoArchiver(@NotNull HelpSystemHelper helper) { + public HelpThreadAutoArchiver(HelpSystemHelper helper) { this.helper = helper; } @Override - public @NotNull Schedule createSchedule() { + @Nonnull + public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, SCHEDULE_MINUTES, TimeUnit.MINUTES); } @Override - public void runRoutine(@NotNull JDA jda) { + public void runRoutine(JDA jda) { jda.getGuildCache().forEach(this::autoArchiveForGuild); } - private void autoArchiveForGuild(@NotNull Guild guild) { + private void autoArchiveForGuild(Guild guild) { Optional maybeOverviewChannel = helper .handleRequireOverviewChannel(guild, channelPattern -> logger.warn( "Unable to auto archive help threads, did not find an overview channel matching the configured pattern '{}' for guild '{}'", @@ -66,12 +67,12 @@ private void autoArchiveForGuild(@NotNull Guild guild) { .forEach(activeThread -> autoArchiveForThread(activeThread, archiveAfterMoment)); } - private @NotNull Instant computeArchiveAfterMoment() { + @Nonnull + private Instant computeArchiveAfterMoment() { return Instant.now().minus(ARCHIVE_AFTER_INACTIVITY_OF); } - private void autoArchiveForThread(@NotNull ThreadChannel threadChannel, - @NotNull Instant archiveAfterMoment) { + private void autoArchiveForThread(ThreadChannel threadChannel, Instant archiveAfterMoment) { if (shouldBeArchived(threadChannel, archiveAfterMoment)) { logger.debug("Auto archiving help thread {}", threadChannel.getId()); @@ -90,8 +91,7 @@ private void autoArchiveForThread(@NotNull ThreadChannel threadChannel, } } - private static boolean shouldBeArchived(MessageChannel channel, - @NotNull Instant archiveAfterMoment) { + private static boolean shouldBeArchived(MessageChannel channel, Instant archiveAfterMoment) { Instant lastActivity = TimeUtil.getTimeCreated(channel.getLatestMessageIdLong()).toInstant(); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadMetadataPurger.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadMetadataPurger.java index 2fa502b76b..4393b837be 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadMetadataPurger.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadMetadataPurger.java @@ -1,12 +1,13 @@ package org.togetherjava.tjbot.commands.help; import net.dv8tion.jda.api.JDA; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.Routine; import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.db.generated.tables.HelpThreads; + +import javax.annotation.Nonnull; import java.time.Instant; import java.time.Period; import java.util.concurrent.TimeUnit; @@ -24,17 +25,18 @@ public class HelpThreadMetadataPurger implements Routine { * * @param database the database used to purge help thread metadata */ - public HelpThreadMetadataPurger(@NotNull Database database) { + public HelpThreadMetadataPurger(Database database) { this.database = database; } @Override - public @NotNull Schedule createSchedule() { + @Nonnull + public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, 4, TimeUnit.HOURS); } @Override - public void runRoutine(@NotNull JDA jda) { + public void runRoutine(JDA jda) { int recordsDeleted = database.writeAndProvide(content -> content.deleteFrom(HelpThreads.HELP_THREADS)) .where(HelpThreads.HELP_THREADS.CREATED_AT diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadOverviewUpdater.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadOverviewUpdater.java index 89eafc0292..0905c4991b 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadOverviewUpdater.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/HelpThreadOverviewUpdater.java @@ -6,14 +6,14 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.internal.requests.CompletedRestAction; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; import org.togetherjava.tjbot.commands.Routine; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -51,7 +51,7 @@ public final class HelpThreadOverviewUpdater extends MessageReceiverAdapter impl * @param config the config to use * @param helper the helper to use */ - public HelpThreadOverviewUpdater(@NotNull Config config, @NotNull HelpSystemHelper helper) { + public HelpThreadOverviewUpdater(Config config, HelpSystemHelper helper) { super(Pattern.compile(config.getHelpSystem().getOverviewChannelPattern())); allCategories = config.getHelpSystem().getCategories(); @@ -59,17 +59,18 @@ public HelpThreadOverviewUpdater(@NotNull Config config, @NotNull HelpSystemHelp } @Override - public @NotNull Schedule createSchedule() { + @Nonnull + public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 1, 1, TimeUnit.MINUTES); } @Override - public void runRoutine(@NotNull JDA jda) { + public void runRoutine(JDA jda) { jda.getGuildCache().forEach(this::updateOverviewForGuild); } @Override - public void onMessageReceived(@NotNull MessageReceivedEvent event) { + public void onMessageReceived(MessageReceivedEvent event) { // Update whenever a thread was created Message message = event.getMessage(); if (message.getType() != MessageType.THREAD_CREATED) { @@ -94,7 +95,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { UPDATE_SERVICE.schedule(updateOverviewCommand, 2, TimeUnit.SECONDS); } - private void updateOverviewForGuild(@NotNull Guild guild) { + private void updateOverviewForGuild(Guild guild) { Optional maybeOverviewChannel = helper .handleRequireOverviewChannel(guild, channelPattern -> logger.warn( "Unable to update help thread overview, did not find an overview channel matching the configured pattern '{}' for guild '{}'", @@ -107,7 +108,7 @@ private void updateOverviewForGuild(@NotNull Guild guild) { updateOverview(maybeOverviewChannel.orElseThrow()); } - private void updateOverview(@NotNull TextChannel overviewChannel) { + private void updateOverview(TextChannel overviewChannel) { logger.debug("Updating overview of active questions"); List activeThreads = helper.getActiveThreadsIn(overviewChannel); @@ -123,7 +124,8 @@ private void updateOverview(@NotNull TextChannel overviewChannel) { .queue(); } - private @NotNull String createDescription(@NotNull Collection activeThreads) { + @Nonnull + private String createDescription(Collection activeThreads) { if (activeThreads.isEmpty()) { return "Currently none."; } @@ -148,8 +150,8 @@ private void updateOverview(@NotNull TextChannel overviewChannel) { .collect(Collectors.joining("\n\n")); } - private static @NotNull RestAction> getStatusMessage( - @NotNull MessageChannel channel) { + @Nonnull + private static RestAction> getStatusMessage(MessageChannel channel) { return channel.getHistory() .retrievePast(1) .map(messages -> messages.stream() @@ -157,7 +159,7 @@ private void updateOverview(@NotNull TextChannel overviewChannel) { .filter(HelpThreadOverviewUpdater::isStatusMessage)); } - private static boolean isStatusMessage(@NotNull Message message) { + private static boolean isStatusMessage(Message message) { if (!message.getAuthor().equals(message.getJDA().getSelfUser())) { return false; } @@ -166,8 +168,9 @@ private static boolean isStatusMessage(@NotNull Message message) { return content.startsWith(STATUS_TITLE); } - private @NotNull RestAction sendUpdatedOverview(@Nullable Message statusMessage, - @NotNull Message updatedStatusMessage, @NotNull MessageChannel overviewChannel) { + @Nonnull + private RestAction sendUpdatedOverview(@Nullable Message statusMessage, + Message updatedStatusMessage, MessageChannel overviewChannel) { logger.debug("Sending the updated question overview"); if (statusMessage == null) { int currentFailures = FIND_STATUS_MESSAGE_CONSECUTIVE_FAILURES.incrementAndGet(); @@ -190,8 +193,7 @@ private static boolean isStatusMessage(@NotNull Message message) { return overviewChannel.editMessageById(statusMessageId, updatedStatusMessage); } - private record CategoryWithThreads(@NotNull String category, - @NotNull List threads) { + private record CategoryWithThreads(String category, List threads) { String toDiscordString() { String threadListText = threads.stream() @@ -201,8 +203,9 @@ String toDiscordString() { return "**%s**:%n%s".formatted(category, threadListText); } - static @NotNull CategoryWithThreads ofEntry( - Map.@NotNull Entry> categoryAndThreads) { + @Nonnull + static CategoryWithThreads ofEntry( + Map.Entry> categoryAndThreads) { return new CategoryWithThreads(categoryAndThreads.getKey(), categoryAndThreads.getValue()); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/ImplicitAskListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/ImplicitAskListener.java index 22a241fbe3..3a9c37452d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/ImplicitAskListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/ImplicitAskListener.java @@ -10,12 +10,12 @@ import net.dv8tion.jda.api.requests.ErrorResponse; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.MessageAction; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Optional; @@ -58,7 +58,7 @@ public final class ImplicitAskListener extends MessageReceiverAdapter { * @param config the config to use * @param helper the helper to use */ - public ImplicitAskListener(@NotNull Config config, @NotNull HelpSystemHelper helper) { + public ImplicitAskListener(Config config, HelpSystemHelper helper) { super(Pattern.compile(config.getHelpSystem().getStagingChannelPattern())); userIdToLastHelpThread = Caffeine.newBuilder() @@ -70,7 +70,7 @@ public ImplicitAskListener(@NotNull Config config, @NotNull HelpSystemHelper hel } @Override - public void onMessageReceived(@NotNull MessageReceivedEvent event) { + public void onMessageReceived(MessageReceivedEvent event) { // Only listen to regular messages from users if (event.isWebhookMessage() || event.getMessage().getType() != MessageType.DEFAULT || event.getAuthor().isBot()) { @@ -101,7 +101,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { }, ImplicitAskListener::handleFailure); } - private boolean handleIsNotOnCooldown(@NotNull Message message) { + private boolean handleIsNotOnCooldown(Message message) { Member author = message.getMember(); Optional maybeLastHelpThread = @@ -125,6 +125,7 @@ private boolean handleIsNotOnCooldown(@NotNull Message message) { return false; } + @Nonnull private Optional getLastHelpThreadIfOnCooldown(long userId) { return Optional.ofNullable(userIdToLastHelpThread.getIfPresent(userId)) .filter(lastHelpThread -> { @@ -136,7 +137,8 @@ private Optional getLastHelpThreadIfOnCooldown(long userId) { }); } - private static @NotNull String createTitle(@NotNull String message) { + @Nonnull + private static String createTitle(String message) { String titleCandidate; if (message.length() < TITLE_MAX_LENGTH) { titleCandidate = message; @@ -154,8 +156,8 @@ private Optional getLastHelpThreadIfOnCooldown(long userId) { return HelpSystemHelper.isTitleValid(titleCandidate) ? titleCandidate : "Untitled"; } - private @NotNull RestAction handleEvent(@NotNull ThreadChannel threadChannel, - @NotNull Message message, @NotNull String title) { + @Nonnull + private RestAction handleEvent(ThreadChannel threadChannel, Message message, String title) { Member author = message.getMember(); helper.writeHelpThreadToDatabase(author, threadChannel); userIdToLastHelpThread.put(author.getIdLong(), @@ -167,13 +169,15 @@ private Optional getLastHelpThreadIfOnCooldown(long userId) { .flatMap(any -> helper.sendExplanationMessage(threadChannel)); } - private static @NotNull RestAction inviteUsersToThread( - @NotNull ThreadChannel threadChannel, @NotNull Member author) { + @Nonnull + private static RestAction inviteUsersToThread(ThreadChannel threadChannel, + Member author) { return threadChannel.addThreadMember(author); } - private static @NotNull MessageAction sendInitialMessage(@NotNull ThreadChannel threadChannel, - @NotNull Message originalMessage, @NotNull String title) { + @Nonnull + private static MessageAction sendInitialMessage(ThreadChannel threadChannel, + Message originalMessage, String title) { String content = originalMessage.getContentRaw(); Member author = originalMessage.getMember(); @@ -194,8 +198,8 @@ private Optional getLastHelpThreadIfOnCooldown(long userId) { return threadChannel.sendMessage(threadMessage); } - private static @NotNull MessageAction notifyUser(@NotNull IMentionable threadChannel, - @NotNull Message message) { + @Nonnull + private static MessageAction notifyUser(IMentionable threadChannel, Message message) { return message.getChannel() .sendMessage( """ @@ -205,7 +209,7 @@ private Optional getLastHelpThreadIfOnCooldown(long userId) { threadChannel.getAsMention())); } - private static void handleFailure(@NotNull Throwable exception) { + private static void handleFailure(Throwable exception) { if (exception instanceof ErrorResponseException responseException) { ErrorResponse response = responseException.getErrorResponse(); if (response == ErrorResponse.MAX_CHANNELS @@ -217,6 +221,6 @@ private static void handleFailure(@NotNull Throwable exception) { logger.error("Attempted to create a help thread, but failed", exception); } - private record HelpThread(long channelId, long authorId, @NotNull Instant creationTime) { + private record HelpThread(long channelId, long authorId, Instant creationTime) { } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/OnGuildLeaveCloseThreadListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/OnGuildLeaveCloseThreadListener.java index 4d8a945f5d..3da99a69e7 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/OnGuildLeaveCloseThreadListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/OnGuildLeaveCloseThreadListener.java @@ -5,15 +5,14 @@ import net.dv8tion.jda.api.entities.ThreadChannel; import net.dv8tion.jda.api.events.guild.member.GuildMemberRemoveEvent; import net.dv8tion.jda.api.hooks.ListenerAdapter; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.EventReceiver; import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.db.generated.tables.HelpThreads; -import javax.annotation.Nonnull; -import java.util.*; +import java.util.HashSet; +import java.util.Set; /** * Remove all thread channels associated to a user when they leave the guild. @@ -28,12 +27,12 @@ public class OnGuildLeaveCloseThreadListener extends ListenerAdapter implements * * @param database database to use */ - public OnGuildLeaveCloseThreadListener(@NotNull Database database) { + public OnGuildLeaveCloseThreadListener(Database database) { this.database = database; } @Override - public void onGuildMemberRemove(@Nonnull GuildMemberRemoveEvent leaveEvent) { + public void onGuildMemberRemove(GuildMemberRemoveEvent leaveEvent) { Set channelIds = getThreadsCreatedByLeaver(leaveEvent.getUser().getIdLong()); for (long channelId : channelIds) { closeThread(channelId, leaveEvent); @@ -48,7 +47,7 @@ private Set getThreadsCreatedByLeaver(long leaverId) { .fetch(databaseMapper -> databaseMapper.getValue(HelpThreads.HELP_THREADS.CHANNEL_ID))); } - private void closeThread(long channelId, @NotNull GuildMemberRemoveEvent leaveEvent) { + private void closeThread(long channelId, GuildMemberRemoveEvent leaveEvent) { ThreadChannel threadChannel = leaveEvent.getGuild().getThreadChannelById(channelId); if (threadChannel == null) { logger.warn( diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/help/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/help/package-info.java index d6deedbaf4..351316091a 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/help/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/help/package-info.java @@ -2,4 +2,7 @@ * This package offers all functionality for the help system. For example commands that let users * ask questions, such as {@link org.togetherjava.tjbot.commands.help.AskCommand}. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.help; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommand.java index 00d1037c57..2b52137b76 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommand.java @@ -6,7 +6,6 @@ import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; -import org.jetbrains.annotations.NotNull; import org.scilab.forge.jlatexmath.ParseException; import org.scilab.forge.jlatexmath.TeXConstants; import org.scilab.forge.jlatexmath.TeXFormula; @@ -15,6 +14,7 @@ import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; +import javax.annotation.Nonnull; import javax.imageio.ImageIO; import java.awt.Color; import java.awt.Image; @@ -62,7 +62,7 @@ public TeXCommand() { } @Override - public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { + public void onSlashCommand(final SlashCommandInteractionEvent event) { String latex = Objects.requireNonNull(event.getOption(LATEX_OPTION)).getAsString(); String userID = (Objects.requireNonNull(event.getMember()).getId()); TeXFormula formula; @@ -97,7 +97,8 @@ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { } } - private @NotNull Image renderImage(@NotNull TeXFormula formula) { + @Nonnull + private Image renderImage(TeXFormula formula) { Image image = formula.createBufferedImage(TeXConstants.STYLE_DISPLAY, DEFAULT_IMAGE_SIZE, FOREGROUND_COLOR, BACKGROUND_COLOR); @@ -107,8 +108,8 @@ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { return image; } - private void sendImage(@NotNull IDeferrableCallback event, @NotNull String userID, - @NotNull Image image) throws IOException { + private void sendImage(IDeferrableCallback event, String userID, Image image) + throws IOException { ByteArrayOutputStream renderedTextImageStream = getRenderedTextImageStream(image); event.getHook() .editOriginal(renderedTextImageStream.toByteArray(), "tex.png") @@ -116,9 +117,8 @@ private void sendImage(@NotNull IDeferrableCallback event, @NotNull String userI .queue(); } - @NotNull - private ByteArrayOutputStream getRenderedTextImageStream(@NotNull Image image) - throws IOException { + @Nonnull + private ByteArrayOutputStream getRenderedTextImageStream(Image image) throws IOException { BufferedImage renderedTextImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_4BYTE_ABGR); @@ -137,8 +137,8 @@ private ByteArrayOutputStream getRenderedTextImageStream(@NotNull Image image) * @param latex the latex to convert * @return the converted latex */ - @NotNull - private String convertInlineLatexToFull(@NotNull String latex) { + @Nonnull + private String convertInlineLatexToFull(String latex) { if (isInvalidInlineFormat(latex)) { throw new ParseException(INVALID_INLINE_FORMAT_ERROR_MESSAGE); } @@ -158,13 +158,12 @@ private String convertInlineLatexToFull(@NotNull String latex) { return sb.toString(); } - private boolean isInvalidInlineFormat(@NotNull String latex) { + private boolean isInvalidInlineFormat(String latex) { return latex.chars().filter(charAsInt -> charAsInt == '$').count() % 2 == 1; } @Override - public void onButtonClick(@NotNull final ButtonInteractionEvent event, - @NotNull final List args) { + public void onButtonClick(final ButtonInteractionEvent event, final List args) { if (!args.get(0).equals(Objects.requireNonNull(event.getMember()).getId())) { event.reply("You are not the person who executed the command, you cannot do that") .setEphemeral(true) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaCommand.java index 90109410c2..8c650b60dc 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaCommand.java @@ -6,7 +6,6 @@ import net.dv8tion.jda.api.interactions.callbacks.IDeferrableCallback; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.requests.restaction.WebhookMessageUpdateAction; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; @@ -39,7 +38,7 @@ public final class WolframAlphaCommand extends SlashCommandAdapter { * * @param config the config to use */ - public WolframAlphaCommand(@NotNull Config config) { + public WolframAlphaCommand(Config config) { super("wolfram-alpha", "Renders mathematical queries using WolframAlpha", SlashCommandVisibility.GUILD); getData().addOption(OptionType.STRING, QUERY_OPTION, "the query to send to WolframAlpha", @@ -48,7 +47,7 @@ public WolframAlphaCommand(@NotNull Config config) { } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { String query = event.getOption(QUERY_OPTION).getAsString(); WolframAlphaHandler handler = new WolframAlphaHandler(query); @@ -73,8 +72,8 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { .thenAccept(response -> sendResponse(response, event)); } - private static void sendResponse(@NotNull WolframAlphaHandler.HandlerResponse response, - @NotNull IDeferrableCallback event) { + private static void sendResponse(WolframAlphaHandler.HandlerResponse response, + IDeferrableCallback event) { WebhookMessageUpdateAction action = event.getHook().editOriginalEmbeds(response.embeds()); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaHandler.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaHandler.java index 7362501427..753e2ddc70 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaHandler.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaHandler.java @@ -4,12 +4,12 @@ import io.mikael.urlbuilder.UrlBuilder; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.entities.MessageEmbed; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.api.Error; import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.api.*; +import javax.annotation.Nonnull; import java.awt.Color; import java.awt.image.BufferedImage; import java.io.IOException; @@ -58,7 +58,7 @@ final class WolframAlphaHandler { * * @param query the original query send to the API */ - WolframAlphaHandler(@NotNull String query) { + WolframAlphaHandler(String query) { this.query = query; userApiQuery = UrlBuilder.fromString(USER_API_ENDPOINT) @@ -73,8 +73,8 @@ final class WolframAlphaHandler { * @param apiResponse response of the Wolfram Alpha API query * @return user-friendly message for display, as list of embeds */ - @NotNull - HandlerResponse handleApiResponse(@NotNull HttpResponse apiResponse) { + @Nonnull + HandlerResponse handleApiResponse(HttpResponse apiResponse) { // Check status code int statusCode = apiResponse.statusCode(); if (statusCode != HttpURLConnection.HTTP_OK) { @@ -111,7 +111,8 @@ HandlerResponse handleApiResponse(@NotNull HttpResponse apiResponse) { return handleSuccessfulResponse(queryResult); } - private @NotNull HandlerResponse handleMisunderstoodQuery(@NotNull QueryResult result) { + @Nonnull + private HandlerResponse handleMisunderstoodQuery(QueryResult result) { StringJoiner output = new StringJoiner("\n"); output.add("Sorry, I did not understand your query."); @@ -151,7 +152,8 @@ HandlerResponse handleApiResponse(@NotNull HttpResponse apiResponse) { return responseOf(output.toString()); } - private static @NotNull String createBulletPointList(Collection elements, + @Nonnull + private static String createBulletPointList(Collection elements, Function elementToText) { return elements.stream() .map(elementToText) @@ -159,7 +161,8 @@ HandlerResponse handleApiResponse(@NotNull HttpResponse apiResponse) { .collect(Collectors.joining("\n")); } - private @NotNull HandlerResponse handleSuccessfulResponse(@NotNull QueryResult queryResult) { + @Nonnull + private HandlerResponse handleSuccessfulResponse(QueryResult queryResult) { StringJoiner messages = new StringJoiner("\n\n"); messages.add("Click the link to see full results."); @@ -198,7 +201,8 @@ HandlerResponse handleApiResponse(@NotNull HttpResponse apiResponse) { return responseOf(messages.toString(), tilesToDisplay); } - private @NotNull HandlerResponse responseOf(@NotNull CharSequence text) { + @Nonnull + private HandlerResponse responseOf(CharSequence text) { MessageEmbed embed = new EmbedBuilder().setTitle(buildTitle(), userApiQuery) .setDescription(text) .setColor(AMBIENT_COLOR) @@ -207,8 +211,9 @@ HandlerResponse handleApiResponse(@NotNull HttpResponse apiResponse) { return new HandlerResponse(List.of(embed), List.of()); } - private @NotNull HandlerResponse responseOf(@NotNull CharSequence text, - @NotNull Collection tiles) { + @Nonnull + private HandlerResponse responseOf(CharSequence text, + Collection tiles) { List embeds = new ArrayList<>(); embeds.add(new EmbedBuilder().setTitle(buildTitle(), userApiQuery) .setDescription(text) @@ -232,16 +237,16 @@ HandlerResponse handleApiResponse(@NotNull HttpResponse apiResponse) { return new HandlerResponse(embeds, attachments); } - private @NotNull String buildTitle() { + @Nonnull + private String buildTitle() { return query + " - " + SERVICE_NAME; } - record HandlerResponse(@NotNull List embeds, - @NotNull List attachments) { + record HandlerResponse(List embeds, List attachments) { } - record Attachment(@NotNull String name, byte @NotNull [] data) { + record Attachment(String name, byte[] data) { @Override public boolean equals(Object o) { if (this == o) { diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaImages.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaImages.java index 47a3a9306e..3adbbf9ed7 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaImages.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/WolframAlphaImages.java @@ -1,9 +1,9 @@ package org.togetherjava.tjbot.commands.mathcommands.wolframalpha; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.api.SubPod; import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.api.WolframAlphaImage; +import javax.annotation.Nonnull; import javax.imageio.ImageIO; import java.awt.Color; import java.awt.Font; @@ -39,7 +39,8 @@ private WolframAlphaImages() { throw new UnsupportedOperationException("Utility class, construction not supported"); } - static @NotNull BufferedImage renderTitle(@NotNull String title) { + @Nonnull + static BufferedImage renderTitle(String title) { Rectangle2D titleBounds = TITLE_FONT.getStringBounds(title, TITLE_RENDER_CONTEXT); int widthPx = (int) Math.ceil(titleBounds.getWidth()) + 2 * IMAGE_MARGIN_PX; int heightPx = (int) Math.ceil(titleBounds.getHeight()) + IMAGE_MARGIN_PX; @@ -55,7 +56,8 @@ private WolframAlphaImages() { return image; } - static @NotNull BufferedImage renderSubPod(@NotNull SubPod subPod) { + @Nonnull + static BufferedImage renderSubPod(SubPod subPod) { WolframAlphaImage sourceImage = subPod.getImage(); int widthPx = sourceImage.getWidth() + 2 * IMAGE_MARGIN_PX; @@ -75,12 +77,14 @@ private WolframAlphaImages() { return destinationImage; } - static @NotNull BufferedImage renderFooter() { + @Nonnull + static BufferedImage renderFooter() { return new BufferedImage(1, IMAGE_MARGIN_PX, BufferedImage.TYPE_4BYTE_ABGR); } - static @NotNull List combineImagesIntoTiles( - @NotNull Collection images, int maxTileHeight) { + @Nonnull + static List combineImagesIntoTiles(Collection images, + int maxTileHeight) { if (images.isEmpty()) { throw new IllegalArgumentException("Images must not be empty"); } @@ -120,8 +124,9 @@ private static boolean wouldTileBeTooLargeIfAddingImage(int tileHeight, int heig return tileHeight != 0 && tileHeight + heightOfImageToAdd > maxTileHeight; } - private static @NotNull BufferedImage combineImages( - @NotNull Collection images, int widthPx) { + @Nonnull + private static BufferedImage combineImages(Collection images, + int widthPx) { if (images.isEmpty()) { throw new IllegalArgumentException("Images must not be empty"); } @@ -146,7 +151,8 @@ private static boolean wouldTileBeTooLargeIfAddingImage(int tileHeight, int heig return destinationImage; } - static byte @NotNull [] imageToBytes(@NotNull RenderedImage img) { + @Nonnull + static byte[] imageToBytes(RenderedImage img) { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { ImageIO.write(img, IMAGE_FORMAT, outputStream); return outputStream.toByteArray(); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/package-info.java index f4513dbb6d..eb5e9633c4 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/package-info.java @@ -3,4 +3,7 @@ * WolframAlpha * API. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.mathcommands.wolframalpha.api; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/package-info.java index d864dfb435..eb9db3d28a 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/package-info.java @@ -2,4 +2,7 @@ * This packages offers all the functionality for the wolfram-alpha command. Sending queries to * their official API, rendering results and displaying them. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.mathcommands.wolframalpha; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ActionRecord.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ActionRecord.java index 910b7c8663..f7ca36833a 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ActionRecord.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ActionRecord.java @@ -1,9 +1,9 @@ package org.togetherjava.tjbot.commands.moderation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.togetherjava.tjbot.db.generated.tables.records.ModerationActionsRecord; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.time.Instant; /** @@ -20,9 +20,8 @@ * {@code null} * @param reason the reason why this action was executed */ -public record ActionRecord(int caseId, @NotNull Instant issuedAt, long guildId, long authorId, - long targetId, @NotNull ModerationAction actionType, @Nullable Instant actionExpiresAt, - @NotNull String reason) { +public record ActionRecord(int caseId, Instant issuedAt, long guildId, long authorId, long targetId, + ModerationAction actionType, @Nullable Instant actionExpiresAt, String reason) { /** * Creates the action record that corresponds to the given action entry from the database table. @@ -30,8 +29,8 @@ public record ActionRecord(int caseId, @NotNull Instant issuedAt, long guildId, * @param action the action to convert * @return the corresponding action record */ - @SuppressWarnings("StaticMethodOnlyUsedInOneClass") - static @NotNull ActionRecord of(@NotNull ModerationActionsRecord action) { + @Nonnull + static ActionRecord of(ModerationActionsRecord action) { return new ActionRecord(action.getCaseId(), action.getIssuedAt(), action.getGuildId(), action.getAuthorId(), action.getTargetId(), ModerationAction.valueOf(action.getActionType()), action.getActionExpiresAt(), diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/AuditCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/AuditCommand.java index 2774271f5f..c59884b593 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/AuditCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/AuditCommand.java @@ -14,11 +14,11 @@ import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.utils.TimeUtil; import net.dv8tion.jda.internal.requests.CompletedRestAction; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.time.Instant; import java.time.ZoneOffset; import java.util.*; @@ -45,7 +45,7 @@ public final class AuditCommand extends SlashCommandAdapter { * * @param actionsStore used to store actions issued by this command */ - public AuditCommand(@NotNull ModerationActionsStore actionsStore) { + public AuditCommand(ModerationActionsStore actionsStore) { super(COMMAND_NAME, "Lists all moderation actions that have been taken against a user", SlashCommandVisibility.GUILD); @@ -56,7 +56,7 @@ public AuditCommand(@NotNull ModerationActionsStore actionsStore) { } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { OptionMapping targetOption = Objects.requireNonNull(event.getOption(TARGET_OPTION), "The target is null"); User target = targetOption.getAsUser(); @@ -73,9 +73,8 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { event.getJDA()).flatMap(event::reply).queue(); } - @SuppressWarnings("BooleanMethodNameMustStartWithQuestion") - private boolean handleChecks(@NotNull Member bot, @NotNull Member author, - @Nullable Member target, @NotNull IReplyCallback event) { + private boolean handleChecks(Member bot, Member author, @Nullable Member target, + IReplyCallback event) { // Member doesn't exist if attempting to audit a user who is not part of the guild. if (target == null) { return true; @@ -88,8 +87,9 @@ private boolean handleChecks(@NotNull Member bot, @NotNull Member author, * can contain {@link AuditCommand#MAX_PAGE_LENGTH} actions, {@code -1} encodes the last * page */ - private @NotNull RestAction auditUser(long guildId, long targetId, long callerId, - int pageNumber, @NotNull JDA jda) { + @Nonnull + private RestAction auditUser(long guildId, long targetId, long callerId, + int pageNumber, JDA jda) { List actions = actionsStore.getActionsByTargetAscending(guildId, targetId); List> groupedActions = groupActionsByPages(actions); int totalPages = groupedActions.size(); @@ -109,8 +109,8 @@ private boolean handleChecks(@NotNull Member bot, @NotNull Member author, guildId, targetId, callerId)); } - private @NotNull List> groupActionsByPages( - @NotNull List actions) { + @Nonnull + private List> groupActionsByPages(List actions) { List> groupedActions = new ArrayList<>(); for (int i = 0; i < actions.size(); i++) { if (i % AuditCommand.MAX_PAGE_LENGTH == 0) { @@ -127,16 +127,16 @@ private static int clamp(int minInclusive, int value, int maxInclusive) { return Math.min(Math.max(minInclusive, value), maxInclusive); } - private static @NotNull EmbedBuilder createSummaryEmbed(@NotNull User user, - @NotNull Collection actions) { + @Nonnull + private static EmbedBuilder createSummaryEmbed(User user, Collection actions) { return new EmbedBuilder().setTitle("Audit log of **%s**".formatted(user.getAsTag())) .setAuthor(user.getName(), null, user.getAvatarUrl()) .setDescription(createSummaryMessageDescription(actions)) .setColor(ModerationUtils.AMBIENT_COLOR); } - private static @NotNull String createSummaryMessageDescription( - @NotNull Collection actions) { + @Nonnull + private static String createSummaryMessageDescription(Collection actions) { int actionAmount = actions.size(); String shortSummary = "There are **%s actions** against the user." @@ -161,9 +161,10 @@ private static int clamp(int minInclusive, int value, int maxInclusive) { return shortSummary + "\n" + typeCountSummary; } - private @NotNull RestAction attachEmbedFields(@NotNull EmbedBuilder auditEmbed, - @NotNull List> groupedActions, int pageNumber, - int totalPages, @NotNull JDA jda) { + @Nonnull + private RestAction attachEmbedFields(EmbedBuilder auditEmbed, + List> groupedActions, int pageNumber, int totalPages, + JDA jda) { if (groupedActions.isEmpty()) { return new CompletedRestAction<>(jda, auditEmbed); } @@ -180,8 +181,8 @@ private static int clamp(int minInclusive, int value, int maxInclusive) { }); } - private static @NotNull RestAction actionToField( - @NotNull ActionRecord action, @NotNull JDA jda) { + @Nonnull + private static RestAction actionToField(ActionRecord action, JDA jda) { return jda.retrieveUserById(action.authorId()) .map(author -> author == null ? "(unknown user)" : author.getAsTag()) .map(authorText -> { @@ -199,12 +200,14 @@ private static int clamp(int minInclusive, int value, int maxInclusive) { }); } - private static @NotNull String formatTime(@NotNull Instant when) { + @Nonnull + private static String formatTime(Instant when) { return TimeUtil.getDateTimeString(when.atOffset(ZoneOffset.UTC)); } - private @NotNull Message attachPageTurnButtons(@NotNull EmbedBuilder auditEmbed, int pageNumber, - int totalPages, long guildId, long targetId, long callerId) { + @Nonnull + private Message attachPageTurnButtons(EmbedBuilder auditEmbed, int pageNumber, int totalPages, + long guildId, long targetId, long callerId) { var messageBuilder = new MessageBuilder(auditEmbed.build()); if (totalPages <= 1) { @@ -216,7 +219,8 @@ private static int clamp(int minInclusive, int value, int maxInclusive) { return messageBuilder.setActionRows(pageTurnButtons).build(); } - private @NotNull ActionRow createPageTurnButtons(long guildId, long targetId, long callerId, + @Nonnull + private ActionRow createPageTurnButtons(long guildId, long targetId, long callerId, int pageNumber, int totalPages) { int previousButtonTurnPageBy = -1; Button previousButton = createPageTurnButton(PREVIOUS_BUTTON_LABEL, guildId, targetId, @@ -235,15 +239,16 @@ private static int clamp(int minInclusive, int value, int maxInclusive) { return ActionRow.of(previousButton, nextButton); } - private @NotNull Button createPageTurnButton(@NotNull String label, long guildId, long targetId, - long callerId, long pageNumber, int turnPageBy) { + @Nonnull + private Button createPageTurnButton(String label, long guildId, long targetId, long callerId, + long pageNumber, int turnPageBy) { return Button.primary(generateComponentId(String.valueOf(guildId), String.valueOf(targetId), String.valueOf(callerId), String.valueOf(pageNumber), String.valueOf(turnPageBy)), label); } @Override - public void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List args) { + public void onButtonClick(ButtonInteractionEvent event, List args) { long commandUserId = Long.parseLong(args.get(2)); long buttonUserId = event.getMember().getIdLong(); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/BanCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/BanCommand.java index b59450c4ad..f633921fc9 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/BanCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/BanCommand.java @@ -14,13 +14,13 @@ import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import net.dv8tion.jda.api.utils.Result; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.time.Instant; import java.util.List; import java.util.Objects; @@ -52,7 +52,7 @@ public final class BanCommand extends SlashCommandAdapter { * * @param actionsStore used to store actions issued by this command */ - public BanCommand(@NotNull ModerationActionsStore actionsStore) { + public BanCommand(ModerationActionsStore actionsStore) { super(COMMAND_NAME, "Bans the given user from the server", SlashCommandVisibility.GUILD); OptionData durationData = new OptionData(OptionType.STRING, DURATION_OPTION, @@ -69,8 +69,8 @@ public BanCommand(@NotNull ModerationActionsStore actionsStore) { this.actionsStore = Objects.requireNonNull(actionsStore); } - private static RestAction handleAlreadyBanned(@NotNull Guild.Ban ban, - @NotNull IReplyCallback event) { + private static RestAction handleAlreadyBanned(Guild.Ban ban, + IReplyCallback event) { String reason = ban.getReason(); String reasonText = reason == null || reason.isBlank() ? "" : " (reason: %s)".formatted(reason); @@ -80,9 +80,9 @@ private static RestAction handleAlreadyBanned(@NotNull Guild.Ba return event.reply(message).setEphemeral(true); } - private static RestAction sendDm(@NotNull ISnowflake target, - @Nullable ModerationUtils.TemporaryData temporaryData, @NotNull String reason, - @NotNull Guild guild, @NotNull GenericEvent event) { + private static RestAction sendDm(ISnowflake target, + @Nullable ModerationUtils.TemporaryData temporaryData, String reason, Guild guild, + GenericEvent event) { String durationMessage = temporaryData == null ? "permanently" : "for " + temporaryData.duration(); String dmMessage = @@ -100,9 +100,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, .map(Result::isSuccess); } - private static @NotNull MessageEmbed sendFeedback(boolean hasSentDm, @NotNull User target, - @NotNull Member author, @Nullable ModerationUtils.TemporaryData temporaryData, - @NotNull String reason) { + @Nonnull + private static MessageEmbed sendFeedback(boolean hasSentDm, User target, Member author, + @Nullable ModerationUtils.TemporaryData temporaryData, String reason) { String durationText = "The ban duration is: " + (temporaryData == null ? "permanent" : temporaryData.duration()); String dmNoticeText = ""; @@ -113,9 +113,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, durationText + dmNoticeText, reason); } + @Nonnull private static Optional> handleNotAlreadyBannedResponse( - @NotNull Throwable alreadyBannedFailure, @NotNull IReplyCallback event, - @NotNull Guild guild, @NotNull User target) { + Throwable alreadyBannedFailure, IReplyCallback event, Guild guild, User target) { if (alreadyBannedFailure instanceof ErrorResponseException errorResponseException) { if (errorResponseException.getErrorResponse() == ErrorResponse.UNKNOWN_BAN) { return Optional.empty(); @@ -136,11 +136,10 @@ private static Optional> handleNotAlreadyBannedRespo .setEphemeral(true)); } - @SuppressWarnings("MethodWithTooManyParameters") - private RestAction banUserFlow(@NotNull User target, @NotNull Member author, - @Nullable ModerationUtils.TemporaryData temporaryData, @NotNull String reason, - int deleteHistoryDays, @NotNull Guild guild, - @NotNull SlashCommandInteractionEvent event) { + @Nonnull + private RestAction banUserFlow(User target, Member author, + @Nullable ModerationUtils.TemporaryData temporaryData, String reason, + int deleteHistoryDays, Guild guild, SlashCommandInteractionEvent event) { return sendDm(target, temporaryData, reason, guild, event) .flatMap(hasSentDm -> banUser(target, author, temporaryData, reason, deleteHistoryDays, guild).map(banResult -> hasSentDm)) @@ -148,10 +147,10 @@ private RestAction banUserFlow(@NotNull User target, @NotNull M .flatMap(event::replyEmbeds); } - @SuppressWarnings("MethodWithTooManyParameters") - private AuditableRestAction banUser(@NotNull User target, @NotNull Member author, - @Nullable ModerationUtils.TemporaryData temporaryData, @NotNull String reason, - int deleteHistoryDays, @NotNull Guild guild) { + @Nonnull + private AuditableRestAction banUser(User target, Member author, + @Nullable ModerationUtils.TemporaryData temporaryData, String reason, + int deleteHistoryDays, Guild guild) { String durationMessage = temporaryData == null ? "permanently" : "for " + temporaryData.duration(); logger.info( @@ -167,9 +166,8 @@ private AuditableRestAction banUser(@NotNull User target, @NotNull Member } @SuppressWarnings({"BooleanMethodNameMustStartWithQuestion", "MethodWithTooManyParameters"}) - private boolean handleChecks(@NotNull Member bot, @NotNull Member author, - @Nullable Member target, @NotNull CharSequence reason, @NotNull Guild guild, - @NotNull IReplyCallback event) { + private boolean handleChecks(Member bot, Member author, @Nullable Member target, + CharSequence reason, Guild guild, IReplyCallback event) { // Member doesn't exist if attempting to ban a user who is not part of the guild. if (target != null && !ModerationUtils.handleCanInteractWithTarget(ACTION_VERB, bot, author, target, event)) { @@ -180,14 +178,14 @@ private boolean handleChecks(@NotNull Member bot, @NotNull Member author, return false; } if (!ModerationUtils.handleHasAuthorPermissions(ACTION_VERB, Permission.BAN_MEMBERS, author, - guild, event)) { + event)) { return false; } return ModerationUtils.handleReason(reason, event); } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { OptionMapping targetOption = Objects.requireNonNull(event.getOption(TARGET_OPTION), "The target is null"); User target = targetOption.getAsUser(); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/KickCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/KickCommand.java index 8a079587f9..1b6a7e23ca 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/KickCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/KickCommand.java @@ -12,13 +12,13 @@ import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import net.dv8tion.jda.api.utils.Result; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Objects; /** @@ -41,7 +41,7 @@ public final class KickCommand extends SlashCommandAdapter { * * @param actionsStore used to store actions issued by this command */ - public KickCommand(@NotNull ModerationActionsStore actionsStore) { + public KickCommand(ModerationActionsStore actionsStore) { super(COMMAND_NAME, "Kicks the given user from the server", SlashCommandVisibility.GUILD); getData().addOption(OptionType.USER, TARGET_OPTION, "The user who you want to kick", true) @@ -50,15 +50,14 @@ public KickCommand(@NotNull ModerationActionsStore actionsStore) { this.actionsStore = Objects.requireNonNull(actionsStore); } - private static void handleAbsentTarget(@NotNull IReplyCallback event) { + private static void handleAbsentTarget(IReplyCallback event) { event.reply("I can not kick the given user since they are not part of the guild anymore.") .setEphemeral(true) .queue(); } - private void kickUserFlow(@NotNull Member target, @NotNull Member author, - @NotNull String reason, @NotNull Guild guild, - @NotNull SlashCommandInteractionEvent event) { + private void kickUserFlow(Member target, Member author, String reason, Guild guild, + SlashCommandInteractionEvent event) { sendDm(target, reason, guild, event) .flatMap(hasSentDm -> kickUser(target, author, reason, guild) .map(kickResult -> hasSentDm)) @@ -67,8 +66,9 @@ private void kickUserFlow(@NotNull Member target, @NotNull Member author, .queue(); } - private static RestAction sendDm(@NotNull ISnowflake target, @NotNull String reason, - @NotNull Guild guild, @NotNull GenericEvent event) { + @Nonnull + private static RestAction sendDm(ISnowflake target, String reason, Guild guild, + GenericEvent event) { return event.getJDA() .openPrivateChannelById(target.getId()) .flatMap(channel -> channel.sendMessage( @@ -82,8 +82,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, @NotNull S .map(Result::isSuccess); } - private AuditableRestAction kickUser(@NotNull Member target, @NotNull Member author, - @NotNull String reason, @NotNull Guild guild) { + @Nonnull + private AuditableRestAction kickUser(Member target, Member author, String reason, + Guild guild) { logger.info("'{}' ({}) kicked the user '{}' ({}) from guild '{}' for reason '{}'.", author.getUser().getAsTag(), author.getId(), target.getUser().getAsTag(), target.getId(), guild.getName(), reason); @@ -94,8 +95,9 @@ private AuditableRestAction kickUser(@NotNull Member target, @NotNull Memb return guild.kick(target, reason).reason(reason); } - private static @NotNull MessageEmbed sendFeedback(boolean hasSentDm, @NotNull Member target, - @NotNull Member author, @NotNull String reason) { + @Nonnull + private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, + String reason) { String dmNoticeText = ""; if (!hasSentDm) { dmNoticeText = "(Unable to send them a DM.)"; @@ -104,10 +106,9 @@ private AuditableRestAction kickUser(@NotNull Member target, @NotNull Memb target.getUser(), dmNoticeText, reason); } - @SuppressWarnings({"BooleanMethodNameMustStartWithQuestion", "MethodWithTooManyParameters"}) - private boolean handleChecks(@NotNull Member bot, @NotNull Member author, - @Nullable Member target, @NotNull CharSequence reason, @NotNull Guild guild, - @NotNull IReplyCallback event) { + @Nonnull + private boolean handleChecks(Member bot, Member author, @Nullable Member target, + CharSequence reason, Guild guild, IReplyCallback event) { // Member doesn't exist if attempting to kick a user who is not part of the guild anymore. if (target == null) { handleAbsentTarget(event); @@ -121,14 +122,14 @@ private boolean handleChecks(@NotNull Member bot, @NotNull Member author, return false; } if (!ModerationUtils.handleHasAuthorPermissions(ACTION_VERB, Permission.KICK_MEMBERS, - author, guild, event)) { + author, event)) { return false; } return ModerationUtils.handleReason(reason, event); } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { Member target = Objects.requireNonNull(event.getOption(TARGET_OPTION), "The target is null") .getAsMember(); Member author = Objects.requireNonNull(event.getMember(), "The author is null"); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationAction.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationAction.java index 76121063ef..047a371300 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationAction.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationAction.java @@ -1,6 +1,6 @@ package org.togetherjava.tjbot.commands.moderation; -import org.jetbrains.annotations.NotNull; +import javax.annotation.Nonnull; /** * All available moderation actions. @@ -51,7 +51,7 @@ public enum ModerationAction { * @param verb the verb of the action, as it would be used in a sentence, such as "banned" or * "kicked" */ - ModerationAction(@NotNull String verb) { + ModerationAction(String verb) { this.verb = verb; } @@ -62,7 +62,8 @@ public enum ModerationAction { * * @return the verb of this action */ - public @NotNull String getVerb() { + @Nonnull + public String getVerb() { return verb; } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationActionsStore.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationActionsStore.java index 3ee603b93a..89ffd7c231 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationActionsStore.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationActionsStore.java @@ -1,12 +1,12 @@ package org.togetherjava.tjbot.commands.moderation; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jooq.Condition; import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.db.generated.tables.ModerationActions; import org.togetherjava.tjbot.db.generated.tables.records.ModerationActionsRecord; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.time.Instant; import java.util.List; import java.util.Objects; @@ -35,7 +35,7 @@ public final class ModerationActionsStore { * * @param database the database to write and retrieve actions from */ - public ModerationActionsStore(@NotNull Database database) { + public ModerationActionsStore(Database database) { this.database = Objects.requireNonNull(database); } @@ -45,7 +45,8 @@ public ModerationActionsStore(@NotNull Database database) { * * @return a list of all expired actions, chronologically ascending */ - public @NotNull List getExpiredActionsAscending() { + @Nonnull + public List getExpiredActionsAscending() { return getActionsAscendingWhere( ModerationActions.MODERATION_ACTIONS.ACTION_EXPIRES_AT.isNotNull() .and(ModerationActions.MODERATION_ACTIONS.ACTION_EXPIRES_AT @@ -61,8 +62,8 @@ public ModerationActionsStore(@NotNull Database database) { * @param actionType the type of action to filter for * @return a list of all actions with the given type, chronologically ascending */ - public @NotNull List getActionsByTypeAscending(long guildId, - @NotNull ModerationAction actionType) { + @Nonnull + public List getActionsByTypeAscending(long guildId, ModerationAction actionType) { Objects.requireNonNull(actionType); return getActionsFromGuildAscending(guildId, @@ -78,7 +79,8 @@ public ModerationActionsStore(@NotNull Database database) { * @param targetId the id of the target user to filter for * @return a list of all actions executed against the target, chronologically ascending */ - public @NotNull List getActionsByTargetAscending(long guildId, long targetId) { + @Nonnull + public List getActionsByTargetAscending(long guildId, long targetId) { return getActionsFromGuildAscending(guildId, ModerationActions.MODERATION_ACTIONS.TARGET_ID.eq(targetId)); } @@ -92,7 +94,8 @@ public ModerationActionsStore(@NotNull Database database) { * @param authorId the id of the author user to filter for * @return a list of all actions executed by the author, chronologically ascending */ - public @NotNull List getActionsByAuthorAscending(long guildId, long authorId) { + @Nonnull + public List getActionsByAuthorAscending(long guildId, long authorId) { return getActionsFromGuildAscending(guildId, ModerationActions.MODERATION_ACTIONS.AUTHOR_ID.eq(authorId)); } @@ -107,8 +110,9 @@ public ModerationActionsStore(@NotNull Database database) { * @param actionType the type of the action * @return the last action issued against the given user of the given type, if present */ - public @NotNull Optional findLastActionAgainstTargetByType(long guildId, - long targetId, @NotNull ModerationAction actionType) { + @Nonnull + public Optional findLastActionAgainstTargetByType(long guildId, long targetId, + ModerationAction actionType) { return database .read(context -> context.selectFrom(ModerationActions.MODERATION_ACTIONS) .where(ModerationActions.MODERATION_ACTIONS.GUILD_ID.eq(guildId) @@ -126,7 +130,8 @@ public ModerationActionsStore(@NotNull Database database) { * @param caseId the actions' case id to search for * @return the action with the given case id, if present */ - public @NotNull Optional findActionByCaseId(int caseId) { + @Nonnull + public Optional findActionByCaseId(int caseId) { return database .read(context -> context.selectFrom(ModerationActions.MODERATION_ACTIONS) .where(ModerationActions.MODERATION_ACTIONS.CASE_ID.eq(caseId)) @@ -152,10 +157,8 @@ public ModerationActionsStore(@NotNull Database database) { * @param reason the reason why this action was executed * @return the unique case id associated with the action */ - @SuppressWarnings("MethodWithTooManyParameters") - public int addAction(long guildId, long authorId, long targetId, - @NotNull ModerationAction actionType, @Nullable Instant actionExpiresAt, - @NotNull String reason) { + public int addAction(long guildId, long authorId, long targetId, ModerationAction actionType, + @Nullable Instant actionExpiresAt, String reason) { Objects.requireNonNull(actionType); Objects.requireNonNull(reason); @@ -174,15 +177,16 @@ public int addAction(long guildId, long authorId, long targetId, }); } - private @NotNull List getActionsFromGuildAscending(long guildId, - @NotNull Condition condition) { + @Nonnull + private List getActionsFromGuildAscending(long guildId, Condition condition) { Objects.requireNonNull(condition); return getActionsAscendingWhere( ModerationActions.MODERATION_ACTIONS.GUILD_ID.eq(guildId).and(condition)); } - private @NotNull List getActionsAscendingWhere(@NotNull Condition condition) { + @Nonnull + private List getActionsAscendingWhere(Condition condition) { Objects.requireNonNull(condition); return database.read(context -> context.selectFrom(ModerationActions.MODERATION_ACTIONS) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationUtils.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationUtils.java index 0450e92c49..bf36aed4ed 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationUtils.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/ModerationUtils.java @@ -4,13 +4,13 @@ import net.dv8tion.jda.api.Permission; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.config.Config; -import java.awt.*; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.awt.Color; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalUnit; @@ -51,8 +51,7 @@ private ModerationUtils() { * @param event the event used to respond to the user * @return whether the reason is valid */ - @SuppressWarnings("BooleanMethodNameMustStartWithQuestion") - static boolean handleReason(@NotNull CharSequence reason, @NotNull IReplyCallback event) { + static boolean handleReason(CharSequence reason, IReplyCallback event) { if (reason.length() <= REASON_MAX_LENGTH) { return true; } @@ -78,9 +77,8 @@ static boolean handleReason(@NotNull CharSequence reason, @NotNull IReplyCallbac * @param event the event used to respond to the user * @return Whether the author and bot can interact with the target user */ - @SuppressWarnings("BooleanMethodNameMustStartWithQuestion") - static boolean handleCanInteractWithTarget(@NotNull String actionVerb, @NotNull Member bot, - @NotNull Member author, @NotNull Member target, @NotNull IReplyCallback event) { + static boolean handleCanInteractWithTarget(String actionVerb, Member bot, Member author, + Member target, IReplyCallback event) { String targetTag = target.getUser().getAsTag(); if (!author.canInteract(target)) { event @@ -113,9 +111,8 @@ static boolean handleCanInteractWithTarget(@NotNull String actionVerb, @NotNull * @param event the event used to respond to the user * @return Whether the author and bot can interact with the role */ - @SuppressWarnings("BooleanMethodNameMustStartWithQuestion") - static boolean handleCanInteractWithRole(@NotNull Member bot, @NotNull Member author, - @NotNull Role role, @NotNull IReplyCallback event) { + static boolean handleCanInteractWithRole(Member bot, Member author, Role role, + IReplyCallback event) { if (!author.canInteract(role)) { event .reply("The role %s is too powerful for you to interact with." @@ -148,10 +145,8 @@ static boolean handleCanInteractWithRole(@NotNull Member bot, @NotNull Member au * @param event the event used to respond to the user * @return Whether the bot has the required permission */ - @SuppressWarnings("BooleanMethodNameMustStartWithQuestion") - static boolean handleHasBotPermissions(@NotNull String actionVerb, - @NotNull Permission permission, @NotNull IPermissionHolder bot, @NotNull Guild guild, - @NotNull IReplyCallback event) { + static boolean handleHasBotPermissions(String actionVerb, Permission permission, + IPermissionHolder bot, Guild guild, IReplyCallback event) { if (!bot.hasPermission(permission)) { event .reply("I can not %s users in this guild since I do not have the %s permission." @@ -166,8 +161,7 @@ static boolean handleHasBotPermissions(@NotNull String actionVerb, return true; } - private static void handleAbsentTarget(@NotNull String actionVerb, - @NotNull IReplyCallback event) { + private static void handleAbsentTarget(String actionVerb, IReplyCallback event) { event .reply("I can not %s the given user since they are not part of the guild anymore." .formatted(actionVerb)) @@ -202,11 +196,12 @@ private static void handleAbsentTarget(@NotNull String actionVerb, * @param event the event used to respond to the user * @return Whether the bot and the author have enough permission */ - @SuppressWarnings({"MethodWithTooManyParameters", "BooleanMethodNameMustStartWithQuestion", - "squid:S107"}) - static boolean handleRoleChangeChecks(@Nullable Role role, @NotNull String actionVerb, - @Nullable Member target, @NotNull Member bot, @NotNull Member author, - @NotNull Guild guild, @NotNull CharSequence reason, @NotNull IReplyCallback event) { + // Sonar complains about having too many parameters. Not incorrect, but not easy to work around + // for now + @SuppressWarnings({"MethodWithTooManyParameters", "squid:S107"}) + static boolean handleRoleChangeChecks(@Nullable Role role, String actionVerb, + @Nullable Member target, Member bot, Member author, Guild guild, CharSequence reason, + IReplyCallback event) { if (role == null) { event .reply("Can not %s the user, unable to find the corresponding role on this server" @@ -248,10 +243,8 @@ static boolean handleRoleChangeChecks(@Nullable Role role, @NotNull String actio * @param event the event used to respond to the user * @return Whether the author has the required permission */ - @SuppressWarnings("BooleanMethodNameMustStartWithQuestion") - static boolean handleHasAuthorPermissions(@NotNull String actionVerb, - @NotNull Permission permission, @NotNull IPermissionHolder author, @NotNull Guild guild, - @NotNull IReplyCallback event) { + static boolean handleHasAuthorPermissions(String actionVerb, Permission permission, + IPermissionHolder author, IReplyCallback event) { if (!author.hasPermission(permission)) { event .reply("You can not %s users in this guild since you do not have the %s permission." @@ -277,9 +270,9 @@ static boolean handleHasAuthorPermissions(@NotNull String actionVerb, * @param reason an optional reason for why the action is executed, {@code null} if not desired * @return the created response */ - static @NotNull MessageEmbed createActionResponse(@NotNull User author, - @NotNull ModerationAction action, @NotNull User target, @Nullable String extraMessage, - @Nullable String reason) { + @Nonnull + static MessageEmbed createActionResponse(User author, ModerationAction action, User target, + @Nullable String extraMessage, @Nullable String reason) { String description = "%s **%s** (id: %s).".formatted(action.getVerb(), target.getAsTag(), target.getId()); if (extraMessage != null && !extraMessage.isBlank()) { @@ -301,7 +294,7 @@ static boolean handleHasAuthorPermissions(@NotNull String actionVerb, * @param config the config used to identify the muted role * @return predicate that matches the name of the muted role */ - public static Predicate getIsMutedRolePredicate(@NotNull Config config) { + public static Predicate getIsMutedRolePredicate(Config config) { return Pattern.compile(config.getMutedRolePattern()).asMatchPredicate(); } @@ -312,8 +305,8 @@ public static Predicate getIsMutedRolePredicate(@NotNull Config config) * @param config the config used to identify the muted role * @return the muted role, if found */ - public static @NotNull Optional getMutedRole(@NotNull Guild guild, - @NotNull Config config) { + @Nonnull + public static Optional getMutedRole(Guild guild, Config config) { Predicate isMutedRole = getIsMutedRolePredicate(config); return guild.getRoles().stream().filter(role -> isMutedRole.test(role.getName())).findAny(); } @@ -324,7 +317,7 @@ public static Predicate getIsMutedRolePredicate(@NotNull Config config) * @param config the config used to identify the quarantined role * @return predicate that matches the name of the quarantined role */ - public static Predicate getIsQuarantinedRolePredicate(@NotNull Config config) { + public static Predicate getIsQuarantinedRolePredicate(Config config) { return Pattern.compile(config.getQuarantinedRolePattern()).asMatchPredicate(); } @@ -335,8 +328,8 @@ public static Predicate getIsQuarantinedRolePredicate(@NotNull Config co * @param config the config used to identify the quarantined role * @return the quarantined role, if found */ - public static @NotNull Optional getQuarantinedRole(@NotNull Guild guild, - @NotNull Config config) { + @Nonnull + public static Optional getQuarantinedRole(Guild guild, Config config) { Predicate isQuarantinedRole = getIsQuarantinedRolePredicate(config); return guild.getRoles() .stream() @@ -353,7 +346,8 @@ public static Predicate getIsQuarantinedRolePredicate(@NotNull Config co * @return the temporary data represented by the given duration or empty if the duration is * {@code "permanent"} */ - static @NotNull Optional computeTemporaryData(@NotNull String durationText) { + @Nonnull + static Optional computeTemporaryData(String durationText) { if (PERMANENT_DURATION.equals(durationText)) { return Optional.empty(); } @@ -378,6 +372,6 @@ public static Predicate getIsQuarantinedRolePredicate(@NotNull Config co * @param duration a human-readable text representing the duration of the temporary action, such * as {@code "1 day"}. */ - record TemporaryData(@NotNull Instant expiresAt, @NotNull String duration) { + record TemporaryData(Instant expiresAt, String duration) { } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/MuteCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/MuteCommand.java index 4c9e9622b7..7e3f40977d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/MuteCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/MuteCommand.java @@ -9,14 +9,14 @@ import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import net.dv8tion.jda.api.utils.Result; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.time.Instant; import java.util.List; import java.util.Objects; @@ -48,7 +48,7 @@ public final class MuteCommand extends SlashCommandAdapter { * @param actionsStore used to store actions issued by this command * @param config the config to use for this */ - public MuteCommand(@NotNull ModerationActionsStore actionsStore, @NotNull Config config) { + public MuteCommand(ModerationActionsStore actionsStore, Config config) { super(COMMAND_NAME, "Mutes the given user so that they can not send messages anymore", SlashCommandVisibility.GUILD); @@ -64,13 +64,14 @@ public MuteCommand(@NotNull ModerationActionsStore actionsStore, @NotNull Config this.actionsStore = Objects.requireNonNull(actionsStore); } - private static void handleAlreadyMutedTarget(@NotNull IReplyCallback event) { + private static void handleAlreadyMutedTarget(IReplyCallback event) { event.reply("The user is already muted.").setEphemeral(true).queue(); } - private static RestAction sendDm(@NotNull ISnowflake target, - @Nullable ModerationUtils.TemporaryData temporaryData, @NotNull String reason, - @NotNull Guild guild, @NotNull GenericEvent event) { + @Nonnull + private static RestAction sendDm(ISnowflake target, + @Nullable ModerationUtils.TemporaryData temporaryData, String reason, Guild guild, + GenericEvent event) { String durationMessage = temporaryData == null ? "permanently" : "for " + temporaryData.duration(); String dmMessage = @@ -88,9 +89,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, .map(Result::isSuccess); } - private static @NotNull MessageEmbed sendFeedback(boolean hasSentDm, @NotNull Member target, - @NotNull Member author, @Nullable ModerationUtils.TemporaryData temporaryData, - @NotNull String reason) { + @Nonnull + private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, + @Nullable ModerationUtils.TemporaryData temporaryData, String reason) { String durationText = "The mute duration is: " + (temporaryData == null ? "permanent" : temporaryData.duration()); String dmNoticeText = ""; @@ -101,9 +102,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, target.getUser(), durationText + dmNoticeText, reason); } - private AuditableRestAction muteUser(@NotNull Member target, @NotNull Member author, - @Nullable ModerationUtils.TemporaryData temporaryData, @NotNull String reason, - @NotNull Guild guild) { + @Nonnull + private AuditableRestAction muteUser(Member target, Member author, + @Nullable ModerationUtils.TemporaryData temporaryData, String reason, Guild guild) { String durationMessage = temporaryData == null ? "permanently" : "for " + temporaryData.duration(); logger.info("'{}' ({}) muted the user '{}' ({}) {} in guild '{}' for reason '{}'.", @@ -119,10 +120,9 @@ private AuditableRestAction muteUser(@NotNull Member target, @NotNull Memb .reason(reason); } - @SuppressWarnings("MethodWithTooManyParameters") - private void muteUserFlow(@NotNull Member target, @NotNull Member author, - @Nullable ModerationUtils.TemporaryData temporaryData, @NotNull String reason, - @NotNull Guild guild, @NotNull SlashCommandInteractionEvent event) { + private void muteUserFlow(Member target, Member author, + @Nullable ModerationUtils.TemporaryData temporaryData, String reason, Guild guild, + SlashCommandInteractionEvent event) { sendDm(target, temporaryData, reason, guild, event) .flatMap(hasSentDm -> muteUser(target, author, temporaryData, reason, guild) .map(result -> hasSentDm)) @@ -131,10 +131,8 @@ private void muteUserFlow(@NotNull Member target, @NotNull Member author, .queue(); } - @SuppressWarnings({"BooleanMethodNameMustStartWithQuestion", "MethodWithTooManyParameters"}) - private boolean handleChecks(@NotNull Member bot, @NotNull Member author, - @Nullable Member target, @NotNull CharSequence reason, @NotNull Guild guild, - @NotNull IReplyCallback event) { + private boolean handleChecks(Member bot, Member author, @Nullable Member target, + CharSequence reason, Guild guild, IReplyCallback event) { if (!ModerationUtils.handleRoleChangeChecks( ModerationUtils.getMutedRole(guild, config).orElse(null), ACTION_VERB, target, bot, author, guild, reason, event)) { @@ -152,7 +150,7 @@ private boolean handleChecks(@NotNull Member bot, @NotNull Member author, } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { Member target = Objects.requireNonNull(event.getOption(TARGET_OPTION), "The target is null") .getAsMember(); Member author = Objects.requireNonNull(event.getMember(), "The author is null"); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/NoteCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/NoteCommand.java index 54bcc11426..3d0cc9cf2e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/NoteCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/NoteCommand.java @@ -5,13 +5,12 @@ import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; +import javax.annotation.Nullable; import java.util.Objects; /** @@ -34,7 +33,7 @@ public final class NoteCommand extends SlashCommandAdapter { * * @param actionsStore used to store actions issued by this command */ - public NoteCommand(@NotNull ModerationActionsStore actionsStore) { + public NoteCommand(ModerationActionsStore actionsStore) { super("note", "Writes a note about the given user", SlashCommandVisibility.GUILD); getData() @@ -47,7 +46,7 @@ public NoteCommand(@NotNull ModerationActionsStore actionsStore) { } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { OptionMapping targetOption = event.getOption(USER_OPTION); Member author = event.getMember(); Guild guild = event.getGuild(); @@ -61,9 +60,8 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { sendNote(targetOption.getAsUser(), author, content, guild, event); } - @SuppressWarnings("BooleanMethodNameMustStartWithQuestion") - private boolean handleChecks(@NotNull Member bot, @NotNull Member author, - @Nullable Member target, CharSequence content, @NotNull IReplyCallback event) { + private boolean handleChecks(Member bot, Member author, @Nullable Member target, + CharSequence content, IReplyCallback event) { if (target != null && !ModerationUtils.handleCanInteractWithTarget(ACTION_VERB, bot, author, target, event)) { return false; @@ -72,14 +70,13 @@ private boolean handleChecks(@NotNull Member bot, @NotNull Member author, return ModerationUtils.handleReason(content, event); } - private void sendNote(@NotNull User target, @NotNull Member author, @NotNull String content, - @NotNull ISnowflake guild, @NotNull IReplyCallback event) { + private void sendNote(User target, Member author, String content, ISnowflake guild, + IReplyCallback event) { storeNote(target, author, content, guild); sendFeedback(target, author, content, event); } - private void storeNote(@NotNull User target, @NotNull Member author, @NotNull String content, - @NotNull ISnowflake guild) { + private void storeNote(User target, Member author, String content, ISnowflake guild) { logger.info("'{}' ({}) wrote a note about the user '{}' ({}) with content '{}'.", author.getUser().getAsTag(), author.getId(), target.getAsTag(), target.getId(), content); @@ -88,8 +85,8 @@ private void storeNote(@NotNull User target, @NotNull Member author, @NotNull St ModerationAction.NOTE, null, content); } - private static void sendFeedback(@NotNull User target, @NotNull Member author, - @NotNull String noteContent, @NotNull IReplyCallback event) { + private static void sendFeedback(User target, Member author, String noteContent, + IReplyCallback event) { MessageEmbed feedback = ModerationUtils.createActionResponse(author.getUser(), ModerationAction.NOTE, target, null, noteContent); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/QuarantineCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/QuarantineCommand.java index 3e845c643a..73091d3c2e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/QuarantineCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/QuarantineCommand.java @@ -8,14 +8,14 @@ import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import net.dv8tion.jda.api.utils.Result; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Objects; /** @@ -41,7 +41,7 @@ public final class QuarantineCommand extends SlashCommandAdapter { * @param actionsStore used to store actions issued by this command * @param config the config to use for this */ - public QuarantineCommand(@NotNull ModerationActionsStore actionsStore, @NotNull Config config) { + public QuarantineCommand(ModerationActionsStore actionsStore, Config config) { super(COMMAND_NAME, "Puts the given user under quarantine. They can not interact with anyone anymore then.", SlashCommandVisibility.GUILD); @@ -55,12 +55,13 @@ public QuarantineCommand(@NotNull ModerationActionsStore actionsStore, @NotNull this.actionsStore = Objects.requireNonNull(actionsStore); } - private static void handleAlreadyQuarantinedTarget(@NotNull IReplyCallback event) { + private static void handleAlreadyQuarantinedTarget(IReplyCallback event) { event.reply("The user is already quarantined.").setEphemeral(true).queue(); } - private static RestAction sendDm(@NotNull ISnowflake target, @NotNull String reason, - @NotNull Guild guild, @NotNull GenericEvent event) { + @Nonnull + private static RestAction sendDm(ISnowflake target, String reason, Guild guild, + GenericEvent event) { String dmMessage = """ Hey there, sorry to tell you but unfortunately you have been put under quarantine in the server %s. @@ -77,8 +78,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, @NotNull S .map(Result::isSuccess); } - private static @NotNull MessageEmbed sendFeedback(boolean hasSentDm, @NotNull Member target, - @NotNull Member author, @NotNull String reason) { + @Nonnull + private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, + String reason) { String dmNoticeText = ""; if (!hasSentDm) { dmNoticeText = "\n(Unable to send them a DM.)"; @@ -87,8 +89,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, @NotNull S target.getUser(), dmNoticeText, reason); } - private AuditableRestAction quarantineUser(@NotNull Member target, @NotNull Member author, - @NotNull String reason, @NotNull Guild guild) { + @Nonnull + private AuditableRestAction quarantineUser(Member target, Member author, String reason, + Guild guild) { logger.info("'{}' ({}) quarantined the user '{}' ({}) in guild '{}' for reason '{}'.", author.getUser().getAsTag(), author.getId(), target.getUser().getAsTag(), target.getId(), guild.getName(), reason); @@ -102,9 +105,8 @@ private AuditableRestAction quarantineUser(@NotNull Member target, @NotNul .reason(reason); } - private void quarantineUserFlow(@NotNull Member target, @NotNull Member author, - @NotNull String reason, @NotNull Guild guild, - @NotNull SlashCommandInteractionEvent event) { + private void quarantineUserFlow(Member target, Member author, String reason, Guild guild, + SlashCommandInteractionEvent event) { sendDm(target, reason, guild, event) .flatMap(hasSentDm -> quarantineUser(target, author, reason, guild) .map(result -> hasSentDm)) @@ -113,10 +115,8 @@ private void quarantineUserFlow(@NotNull Member target, @NotNull Member author, .queue(); } - @SuppressWarnings({"BooleanMethodNameMustStartWithQuestion", "MethodWithTooManyParameters"}) - private boolean handleChecks(@NotNull Member bot, @NotNull Member author, - @Nullable Member target, @NotNull CharSequence reason, @NotNull Guild guild, - @NotNull IReplyCallback event) { + private boolean handleChecks(Member bot, Member author, @Nullable Member target, + CharSequence reason, Guild guild, IReplyCallback event) { if (!ModerationUtils.handleRoleChangeChecks( ModerationUtils.getQuarantinedRole(guild, config).orElse(null), ACTION_VERB, target, bot, author, guild, reason, event)) { @@ -136,7 +136,7 @@ private boolean handleChecks(@NotNull Member bot, @NotNull Member author, } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { Member target = event.getOption(TARGET_OPTION).getAsMember(); Member author = event.getMember(); String reason = event.getOption(REASON_OPTION).getAsString(); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/RejoinModerationRoleListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/RejoinModerationRoleListener.java index 2d306f0247..0df83b86d3 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/RejoinModerationRoleListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/RejoinModerationRoleListener.java @@ -6,7 +6,6 @@ import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.events.GenericEvent; import net.dv8tion.jda.api.events.guild.member.GuildMemberJoinEvent; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.EventReceiver; @@ -39,8 +38,7 @@ public final class RejoinModerationRoleListener implements EventReceiver { * user should be e.g. muted * @param config the config to use for this */ - public RejoinModerationRoleListener(@NotNull ModerationActionsStore actionsStore, - @NotNull Config config) { + public RejoinModerationRoleListener(ModerationActionsStore actionsStore, Config config) { this.actionsStore = actionsStore; moderationRoles = List.of( @@ -52,13 +50,13 @@ public RejoinModerationRoleListener(@NotNull ModerationActionsStore actionsStore } @Override - public void onEvent(@NotNull GenericEvent event) { + public void onEvent(GenericEvent event) { if (event instanceof GuildMemberJoinEvent joinEvent) { onGuildMemberJoin(joinEvent); } } - private void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) { + private void onGuildMemberJoin(GuildMemberJoinEvent event) { Member member = event.getMember(); for (ModerationRole moderationRole : moderationRoles) { @@ -68,8 +66,8 @@ private void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) { } } - private boolean shouldApplyModerationRole(@NotNull ModerationRole moderationRole, - @NotNull IPermissionHolder member) { + private boolean shouldApplyModerationRole(ModerationRole moderationRole, + IPermissionHolder member) { Optional lastApplyAction = actionsStore.findLastActionAgainstTargetByType( member.getGuild().getIdLong(), member.getIdLong(), moderationRole.applyAction); if (lastApplyAction.isEmpty()) { @@ -93,8 +91,7 @@ private boolean shouldApplyModerationRole(@NotNull ModerationRole moderationRole return false; } - private static void applyModerationRole(@NotNull ModerationRole moderationRole, - @NotNull Member member) { + private static void applyModerationRole(ModerationRole moderationRole, Member member) { Guild guild = member.getGuild(); logger.info("Reapplied existing {} to user '{}' ({}) in guild '{}' after rejoining.", moderationRole.actionName, member.getUser().getAsTag(), member.getId(), @@ -106,7 +103,7 @@ private static void applyModerationRole(@NotNull ModerationRole moderationRole, .queue(); } - private record ModerationRole(@NotNull String actionName, @NotNull ModerationAction applyAction, - @NotNull ModerationAction revokeAction, @NotNull Function guildToRole) { + private record ModerationRole(String actionName, ModerationAction applyAction, + ModerationAction revokeAction, Function guildToRole) { } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnbanCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnbanCommand.java index 654ac014e9..e9a6ad2bd6 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnbanCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnbanCommand.java @@ -7,7 +7,6 @@ import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.requests.ErrorResponse; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; @@ -32,7 +31,7 @@ public final class UnbanCommand extends SlashCommandAdapter { * * @param actionsStore used to store actions issued by this command */ - public UnbanCommand(@NotNull ModerationActionsStore actionsStore) { + public UnbanCommand(ModerationActionsStore actionsStore) { super(COMMAND_NAME, "Unbans the given user from the server", SlashCommandVisibility.GUILD); getData() @@ -43,8 +42,8 @@ public UnbanCommand(@NotNull ModerationActionsStore actionsStore) { this.actionsStore = Objects.requireNonNull(actionsStore); } - private void unban(@NotNull User target, @NotNull Member author, @NotNull String reason, - @NotNull Guild guild, @NotNull IReplyCallback event) { + private void unban(User target, Member author, String reason, Guild guild, + IReplyCallback event) { guild.unban(target).reason(reason).queue(result -> { MessageEmbed message = ModerationUtils.createActionResponse(author.getUser(), ModerationAction.UNBAN, target, null, reason); @@ -59,8 +58,7 @@ private void unban(@NotNull User target, @NotNull Member author, @NotNull String }, unbanFailure -> handleFailure(unbanFailure, target, event)); } - private static void handleFailure(@NotNull Throwable unbanFailure, @NotNull User target, - @NotNull IReplyCallback event) { + private static void handleFailure(Throwable unbanFailure, User target, IReplyCallback event) { String targetTag = target.getAsTag(); if (unbanFailure instanceof ErrorResponseException errorResponseException) { if (errorResponseException.getErrorResponse() == ErrorResponse.UNKNOWN_USER) { @@ -82,15 +80,14 @@ private static void handleFailure(@NotNull Throwable unbanFailure, @NotNull User targetTag, unbanFailure); } - @SuppressWarnings({"BooleanMethodNameMustStartWithQuestion"}) - private boolean handleChecks(@NotNull IPermissionHolder bot, @NotNull Member author, - @NotNull CharSequence reason, @NotNull Guild guild, @NotNull IReplyCallback event) { + private boolean handleChecks(IPermissionHolder bot, Member author, CharSequence reason, + Guild guild, IReplyCallback event) { if (!ModerationUtils.handleHasBotPermissions(ACTION_VERB, Permission.BAN_MEMBERS, bot, guild, event)) { return false; } if (!ModerationUtils.handleHasAuthorPermissions(ACTION_VERB, Permission.BAN_MEMBERS, author, - guild, event)) { + event)) { return false; } @@ -98,7 +95,7 @@ private boolean handleChecks(@NotNull IPermissionHolder bot, @NotNull Member aut } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { User target = Objects.requireNonNull(event.getOption(TARGET_OPTION), "The target is null") .getAsUser(); Member author = Objects.requireNonNull(event.getMember(), "The author is null"); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnmuteCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnmuteCommand.java index d2b3041660..f0414df212 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnmuteCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnmuteCommand.java @@ -8,14 +8,14 @@ import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import net.dv8tion.jda.api.utils.Result; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Objects; /** @@ -40,7 +40,7 @@ public final class UnmuteCommand extends SlashCommandAdapter { * @param actionsStore used to store actions issued by this command * @param config the config to use for this */ - public UnmuteCommand(@NotNull ModerationActionsStore actionsStore, @NotNull Config config) { + public UnmuteCommand(ModerationActionsStore actionsStore, Config config) { super(COMMAND_NAME, "Unmutes the given already muted user so that they can send messages again", SlashCommandVisibility.GUILD); @@ -52,12 +52,13 @@ public UnmuteCommand(@NotNull ModerationActionsStore actionsStore, @NotNull Conf this.actionsStore = Objects.requireNonNull(actionsStore); } - private static void handleNotMutedTarget(@NotNull IReplyCallback event) { + private static void handleNotMutedTarget(IReplyCallback event) { event.reply("The user is not muted.").setEphemeral(true).queue(); } - private static RestAction sendDm(@NotNull ISnowflake target, @NotNull String reason, - @NotNull Guild guild, @NotNull GenericEvent event) { + @Nonnull + private static RestAction sendDm(ISnowflake target, String reason, Guild guild, + GenericEvent event) { String dmMessage = """ Hey there, you have been unmuted in the server %s. This means you can now send messages in the server again. @@ -70,8 +71,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, @NotNull S .map(Result::isSuccess); } - private static @NotNull MessageEmbed sendFeedback(boolean hasSentDm, @NotNull Member target, - @NotNull Member author, @NotNull String reason) { + @Nonnull + private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, + String reason) { String dmNoticeText = ""; if (!hasSentDm) { dmNoticeText = "(Unable to send them a DM.)"; @@ -80,8 +82,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, @NotNull S target.getUser(), dmNoticeText, reason); } - private AuditableRestAction unmuteUser(@NotNull Member target, @NotNull Member author, - @NotNull String reason, @NotNull Guild guild) { + @Nonnull + private AuditableRestAction unmuteUser(Member target, Member author, String reason, + Guild guild) { logger.info("'{}' ({}) unmuted the user '{}' ({}) in guild '{}' for reason '{}'.", author.getUser().getAsTag(), author.getId(), target.getUser().getAsTag(), target.getId(), guild.getName(), reason); @@ -94,9 +97,8 @@ private AuditableRestAction unmuteUser(@NotNull Member target, @NotNull Me .reason(reason); } - private void unmuteUserFlow(@NotNull Member target, @NotNull Member author, - @NotNull String reason, @NotNull Guild guild, - @NotNull SlashCommandInteractionEvent event) { + private void unmuteUserFlow(Member target, Member author, String reason, Guild guild, + SlashCommandInteractionEvent event) { sendDm(target, reason, guild, event) .flatMap( hasSentDm -> unmuteUser(target, author, reason, guild).map(result -> hasSentDm)) @@ -105,10 +107,8 @@ private void unmuteUserFlow(@NotNull Member target, @NotNull Member author, .queue(); } - @SuppressWarnings({"BooleanMethodNameMustStartWithQuestion", "MethodWithTooManyParameters"}) - private boolean handleChecks(@NotNull Member bot, @NotNull Member author, - @Nullable Member target, @NotNull CharSequence reason, @NotNull Guild guild, - @NotNull IReplyCallback event) { + private boolean handleChecks(Member bot, Member author, @Nullable Member target, + CharSequence reason, Guild guild, IReplyCallback event) { if (!ModerationUtils.handleRoleChangeChecks( ModerationUtils.getMutedRole(guild, config).orElse(null), ACTION_VERB, target, bot, author, guild, reason, event)) { @@ -126,7 +126,7 @@ private boolean handleChecks(@NotNull Member bot, @NotNull Member author, } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { Member target = Objects.requireNonNull(event.getOption(TARGET_OPTION), "The target is null") .getAsMember(); Member author = Objects.requireNonNull(event.getMember(), "The author is null"); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnquarantineCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnquarantineCommand.java index c04b173f96..117d61d5ce 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnquarantineCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/UnquarantineCommand.java @@ -8,14 +8,14 @@ import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import net.dv8tion.jda.api.utils.Result; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Objects; /** @@ -41,8 +41,7 @@ public final class UnquarantineCommand extends SlashCommandAdapter { * @param actionsStore used to store actions issued by this command * @param config the config to use for this */ - public UnquarantineCommand(@NotNull ModerationActionsStore actionsStore, - @NotNull Config config) { + public UnquarantineCommand(ModerationActionsStore actionsStore, Config config) { super(COMMAND_NAME, "Unquarantines the given already quarantined user so that they can interact again", SlashCommandVisibility.GUILD); @@ -57,12 +56,13 @@ public UnquarantineCommand(@NotNull ModerationActionsStore actionsStore, this.actionsStore = Objects.requireNonNull(actionsStore); } - private static void handleNotQuarantinedTarget(@NotNull IReplyCallback event) { + private static void handleNotQuarantinedTarget(IReplyCallback event) { event.reply("The user is not quarantined.").setEphemeral(true).queue(); } - private static RestAction sendDm(@NotNull ISnowflake target, @NotNull String reason, - @NotNull Guild guild, @NotNull GenericEvent event) { + @Nonnull + private static RestAction sendDm(ISnowflake target, String reason, Guild guild, + GenericEvent event) { String dmMessage = """ Hey there, you have been put out of quarantine in the server %s. This means you can now interact with others in the server again. @@ -76,8 +76,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, @NotNull S .map(Result::isSuccess); } - private static @NotNull MessageEmbed sendFeedback(boolean hasSentDm, @NotNull Member target, - @NotNull Member author, @NotNull String reason) { + @Nonnull + private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, + String reason) { String dmNoticeText = ""; if (!hasSentDm) { dmNoticeText = "(Unable to send them a DM.)"; @@ -86,8 +87,9 @@ private static RestAction sendDm(@NotNull ISnowflake target, @NotNull S target.getUser(), dmNoticeText, reason); } - private AuditableRestAction unquarantineUser(@NotNull Member target, - @NotNull Member author, @NotNull String reason, @NotNull Guild guild) { + @Nonnull + private AuditableRestAction unquarantineUser(Member target, Member author, String reason, + Guild guild) { logger.info("'{}' ({}) unquarantined the user '{}' ({}) in guild '{}' for reason '{}'.", author.getUser().getAsTag(), author.getId(), target.getUser().getAsTag(), target.getId(), guild.getName(), reason); @@ -101,9 +103,8 @@ private AuditableRestAction unquarantineUser(@NotNull Member target, .reason(reason); } - private void unquarantineUserFlow(@NotNull Member target, @NotNull Member author, - @NotNull String reason, @NotNull Guild guild, - @NotNull SlashCommandInteractionEvent event) { + private void unquarantineUserFlow(Member target, Member author, String reason, Guild guild, + SlashCommandInteractionEvent event) { sendDm(target, reason, guild, event) .flatMap(hasSentDm -> unquarantineUser(target, author, reason, guild) .map(result -> hasSentDm)) @@ -112,10 +113,8 @@ private void unquarantineUserFlow(@NotNull Member target, @NotNull Member author .queue(); } - @SuppressWarnings({"BooleanMethodNameMustStartWithQuestion", "MethodWithTooManyParameters"}) - private boolean handleChecks(@NotNull Member bot, @NotNull Member author, - @Nullable Member target, @NotNull CharSequence reason, @NotNull Guild guild, - @NotNull IReplyCallback event) { + private boolean handleChecks(Member bot, Member author, @Nullable Member target, + CharSequence reason, Guild guild, IReplyCallback event) { if (!ModerationUtils.handleRoleChangeChecks( ModerationUtils.getQuarantinedRole(guild, config).orElse(null), ACTION_VERB, target, bot, author, guild, reason, event)) { @@ -135,7 +134,7 @@ private boolean handleChecks(@NotNull Member bot, @NotNull Member author, } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { Member target = event.getOption(TARGET_OPTION).getAsMember(); Member author = event.getMember(); String reason = event.getOption(REASON_OPTION).getAsString(); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/WarnCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/WarnCommand.java index a29b1ea51d..a852a56728 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/WarnCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/WarnCommand.java @@ -7,13 +7,13 @@ import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.utils.Result; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Objects; /** @@ -35,7 +35,7 @@ public final class WarnCommand extends SlashCommandAdapter { * * @param actionsStore used to store actions issued by this command */ - public WarnCommand(@NotNull ModerationActionsStore actionsStore) { + public WarnCommand(ModerationActionsStore actionsStore) { super("warn", "Warns the given user", SlashCommandVisibility.GUILD); getData().addOption(OptionType.USER, USER_OPTION, "The user who you want to warn", true) @@ -44,9 +44,9 @@ public WarnCommand(@NotNull ModerationActionsStore actionsStore) { this.actionsStore = Objects.requireNonNull(actionsStore); } - private @NotNull RestAction warnUserFlow(@NotNull User target, - @NotNull Member author, @NotNull String reason, @NotNull Guild guild, - @NotNull SlashCommandInteractionEvent event) { + @Nonnull + private RestAction warnUserFlow(User target, Member author, String reason, + Guild guild, SlashCommandInteractionEvent event) { return dmUser(target, reason, guild, event).map(hasSentDm -> { warnUser(target, author, reason, guild); return hasSentDm; @@ -55,9 +55,9 @@ public WarnCommand(@NotNull ModerationActionsStore actionsStore) { .flatMap(event::replyEmbeds); } - private static @NotNull RestAction dmUser(@NotNull ISnowflake target, - @NotNull String reason, @NotNull Guild guild, - @NotNull SlashCommandInteractionEvent event) { + @Nonnull + private static RestAction dmUser(ISnowflake target, String reason, Guild guild, + SlashCommandInteractionEvent event) { return event.getJDA() .openPrivateChannelById(target.getId()) .flatMap(channel -> channel.sendMessage( @@ -71,8 +71,7 @@ public WarnCommand(@NotNull ModerationActionsStore actionsStore) { .map(Result::isSuccess); } - private void warnUser(@NotNull User target, @NotNull Member author, @NotNull String reason, - @NotNull Guild guild) { + private void warnUser(User target, Member author, String reason, Guild guild) { logger.info("'{}' ({}) warned the user '{}' ({}) for reason '{}'.", author.getUser().getAsTag(), author.getId(), target.getAsTag(), target.getId(), reason); @@ -81,8 +80,9 @@ private void warnUser(@NotNull User target, @NotNull Member author, @NotNull Str ModerationAction.WARN, null, reason); } - private static @NotNull MessageEmbed sendFeedback(boolean hasSentDm, @NotNull User target, - @NotNull Member author, @NotNull String reason) { + @Nonnull + private static MessageEmbed sendFeedback(boolean hasSentDm, User target, Member author, + String reason) { String dmNoticeText = ""; if (!hasSentDm) { dmNoticeText = "(Unable to send them a DM.)"; @@ -92,7 +92,7 @@ private void warnUser(@NotNull User target, @NotNull Member author, @NotNull Str } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { OptionMapping targetOption = Objects.requireNonNull(event.getOption(USER_OPTION), "The target is null"); Member author = Objects.requireNonNull(event.getMember(), "The author is null"); @@ -108,9 +108,8 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { warnUserFlow(targetOption.getAsUser(), author, reason, guild, event).queue(); } - @SuppressWarnings("BooleanMethodNameMustStartWithQuestion") - private boolean handleChecks(@NotNull Member bot, @NotNull Member author, - @Nullable Member target, String reason, @NotNull SlashCommandInteractionEvent event) { + private boolean handleChecks(Member bot, Member author, @Nullable Member target, String reason, + SlashCommandInteractionEvent event) { if (target != null && !ModerationUtils.handleCanInteractWithTarget(ACTION_VERB, bot, author, target, event)) { return false; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/WhoIsCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/WhoIsCommand.java index 4403353880..c54cefb97e 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/WhoIsCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/WhoIsCommand.java @@ -8,12 +8,12 @@ import net.dv8tion.jda.api.interactions.commands.OptionMapping; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.commands.utils.DiscordClientAction; import javax.annotation.CheckReturnValue; +import javax.annotation.Nonnull; import java.awt.Color; import java.time.Instant; import java.time.OffsetDateTime; @@ -49,7 +49,7 @@ public WhoIsCommand() { } @Override - public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { + public void onSlashCommand(final SlashCommandInteractionEvent event) { OptionMapping userOption = Objects.requireNonNull(event.getOption(USER_OPTION), "The given user option cannot be null"); OptionMapping showServerSpecificInfoOption = event.getOption(SHOW_SERVER_INFO_OPTION); @@ -70,8 +70,9 @@ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { } @CheckReturnValue - private static @NotNull ReplyCallbackAction handleWhoIsUser(final @NotNull IReplyCallback event, - final @NotNull User user, final @NotNull User.Profile profile) { + @Nonnull + private static ReplyCallbackAction handleWhoIsUser(final IReplyCallback event, final User user, + final User.Profile profile) { String description = userIdentificationToStringItem(user) + "\n**Is bot:** " + user.isBot() + userFlagsToStringItem(user.getFlags()) + "\n**Registration date:** " + DATE_TIME_FORMAT.format(user.getTimeCreated()); @@ -85,9 +86,9 @@ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { } @CheckReturnValue - private static @NotNull ReplyCallbackAction handleWhoIsMember( - final @NotNull IReplyCallback event, final @NotNull Member member, - final @NotNull User.Profile profile) { + @Nonnull + private static ReplyCallbackAction handleWhoIsMember(final IReplyCallback event, + final Member member, final User.Profile profile) { User user = member.getUser(); Color memberColor = member.getColor(); @@ -108,15 +109,16 @@ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { return sendEmbedWithProfileAction(event, embedBuilder.build(), user.getId()); } - private static @NotNull ReplyCallbackAction sendEmbedWithProfileAction( - final @NotNull IReplyCallback event, @NotNull MessageEmbed embed, - @NotNull String userId) { + @Nonnull + private static ReplyCallbackAction sendEmbedWithProfileAction(final IReplyCallback event, + MessageEmbed embed, String userId) { return event.replyEmbeds(embed) .addActionRow( DiscordClientAction.General.USER.asLinkButton("Click to see profile!", userId)); } - private static @NotNull String voiceStateToStringItem(@NotNull final Member member) { + @Nonnull + private static String voiceStateToStringItem(final Member member) { GuildVoiceState voiceState = Objects.requireNonNull(member.getVoiceState(), "The given voiceState cannot be null"); @@ -137,9 +139,9 @@ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { * @param effectiveColor the {@link Color} that the embed will become * @return the generated {@link EmbedBuilder} */ - private static @NotNull EmbedBuilder generateEmbedBuilder(@NotNull final Interaction event, - @NotNull final User user, final @NotNull User.Profile profile, - final Color effectiveColor) { + @Nonnull + private static EmbedBuilder generateEmbedBuilder(final Interaction event, final User user, + final User.Profile profile, final Color effectiveColor) { EmbedBuilder embedBuilder = new EmbedBuilder().setThumbnail(user.getEffectiveAvatarUrl()) .setColor(effectiveColor) @@ -160,7 +162,8 @@ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { * @param member the {@link Member} to take the booster properties from * @return user readable {@link String} */ - private static @NotNull String possibleBoosterToStringItem(final @NotNull Member member) { + @Nonnull + private static String possibleBoosterToStringItem(final Member member) { OffsetDateTime timeBoosted = member.getTimeBoosted(); if (null == timeBoosted) { @@ -177,7 +180,8 @@ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { * @param user the {@link User} to take the identifiers from * @return user readable {@link String} */ - private static @NotNull String userIdentificationToStringItem(final @NotNull User user) { + @Nonnull + private static String userIdentificationToStringItem(final User user) { return "**Mention:** " + user.getAsMention() + "\n**Tag:** " + user.getAsTag() + "\n**ID:** " + user.getId(); } @@ -188,7 +192,8 @@ public void onSlashCommand(@NotNull final SlashCommandInteractionEvent event) { * @param member member to take the Roles from * @return user readable {@link String} of the roles */ - private static String formatRoles(final @NotNull Member member) { + @Nonnull + private static String formatRoles(final Member member) { return member.getRoles().stream().map(Role::getAsMention).collect(Collectors.joining(", ")); } @@ -199,8 +204,8 @@ private static String formatRoles(final @NotNull Member member) { * (recommend {@link java.util.EnumSet} * @return user readable {@link StringBuilder} */ - private static @NotNull StringBuilder userFlagsToStringItem( - final @NotNull Collection flags) { + @Nonnull + private static StringBuilder userFlagsToStringItem(final Collection flags) { String formattedFlags = formatUserFlags(flags); StringBuilder result = hypeSquadToStringItem(flags); @@ -218,8 +223,8 @@ private static String formatRoles(final @NotNull Member member) { * (recommend {@link java.util.EnumSet} * @return user readable {@link StringBuilder} */ - private static @NotNull StringBuilder hypeSquadToStringItem( - final @NotNull Collection flags) { + @Nonnull + private static StringBuilder hypeSquadToStringItem(final Collection flags) { StringBuilder stringBuilder = new StringBuilder("**\nHypesquad:** "); if (flags.contains(User.UserFlag.HYPESQUAD_BALANCE)) { @@ -242,8 +247,8 @@ private static String formatRoles(final @NotNull Member member) { * (recommend {@link java.util.EnumSet} * @return the user readable string */ - @NotNull - private static String formatUserFlags(final @NotNull Collection flags) { + @Nonnull + private static String formatUserFlags(final Collection flags) { return flags.stream() .map(User.UserFlag::getName) .filter(name -> (name.contains("Hypesquad"))) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/package-info.java index 399fc1fa1f..779ef299a7 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/package-info.java @@ -2,4 +2,7 @@ * This package offers all the moderation commands from the application such as banning and kicking * users. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.moderation; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamBlocker.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamBlocker.java index e4240cedb2..7c1e812d0d 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamBlocker.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamBlocker.java @@ -12,8 +12,6 @@ import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import net.dv8tion.jda.api.requests.ErrorResponse; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; @@ -28,6 +26,8 @@ import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.config.ScamBlockerConfig; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.awt.Color; import java.util.*; import java.util.function.Consumer; @@ -66,8 +66,8 @@ public final class ScamBlocker extends MessageReceiverAdapter implements UserInt * @param scamHistoryStore to store and retrieve scam history from * @param config the config to use for this */ - public ScamBlocker(@NotNull ModerationActionsStore actionsStore, - @NotNull ScamHistoryStore scamHistoryStore, @NotNull Config config) { + public ScamBlocker(ModerationActionsStore actionsStore, ScamHistoryStore scamHistoryStore, + Config config) { super(Pattern.compile(".*")); this.actionsStore = actionsStore; @@ -84,23 +84,23 @@ public ScamBlocker(@NotNull ModerationActionsStore actionsStore, } @Override - public @NotNull String getName() { + @Nonnull + public String getName() { return "scam-blocker"; } @Override - public void onSelectionMenu(@NotNull SelectMenuInteractionEvent event, - @NotNull List args) { + public void onSelectionMenu(SelectMenuInteractionEvent event, List args) { throw new UnsupportedOperationException("Not used"); } @Override - public void acceptComponentIdGenerator(@NotNull ComponentIdGenerator generator) { + public void acceptComponentIdGenerator(ComponentIdGenerator generator) { componentIdGenerator = generator; } @Override - public void onMessageReceived(@NotNull MessageReceivedEvent event) { + public void onMessageReceived(MessageReceivedEvent event) { if (event.getAuthor().isBot() || event.isWebhookMessage()) { return; } @@ -123,7 +123,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { takeAction(event); } - private void takeActionWasAlreadyReported(@NotNull MessageReceivedEvent event) { + private void takeActionWasAlreadyReported(MessageReceivedEvent event) { // The user recently send the same scam already, and that was already reported and handled addScamToHistory(event); @@ -133,7 +133,7 @@ private void takeActionWasAlreadyReported(@NotNull MessageReceivedEvent event) { } } - private void takeAction(@NotNull MessageReceivedEvent event) { + private void takeAction(MessageReceivedEvent event) { switch (mode) { case OFF -> throw new AssertionError( "The OFF-mode should be detected earlier already to prevent expensive computation"); @@ -146,25 +146,25 @@ private void takeAction(@NotNull MessageReceivedEvent event) { } } - private void takeActionLogOnly(@NotNull MessageReceivedEvent event) { + private void takeActionLogOnly(MessageReceivedEvent event) { addScamToHistory(event); logScamMessage(event); } - private void takeActionApproveFirst(@NotNull MessageReceivedEvent event) { + private void takeActionApproveFirst(MessageReceivedEvent event) { addScamToHistory(event); logScamMessage(event); reportScamMessage(event, "Is this scam?", createConfirmDialog(event)); } - private void takeActionAutoDeleteButApproveQuarantine(@NotNull MessageReceivedEvent event) { + private void takeActionAutoDeleteButApproveQuarantine(MessageReceivedEvent event) { addScamToHistory(event); logScamMessage(event); deleteMessage(event); reportScamMessage(event, "Is this scam? (already deleted)", createConfirmDialog(event)); } - private void takeActionAutoDeleteAndQuarantine(@NotNull MessageReceivedEvent event) { + private void takeActionAutoDeleteAndQuarantine(MessageReceivedEvent event) { addScamToHistory(event); logScamMessage(event); deleteMessage(event); @@ -173,26 +173,25 @@ private void takeActionAutoDeleteAndQuarantine(@NotNull MessageReceivedEvent eve reportScamMessage(event, "Detected and handled scam", null); } - private void addScamToHistory(@NotNull MessageReceivedEvent event) { + private void addScamToHistory(MessageReceivedEvent event) { scamHistoryStore.addScam(event.getMessage(), MODES_WITH_IMMEDIATE_DELETION.contains(mode)); } - private void logScamMessage(@NotNull MessageReceivedEvent event) { + private void logScamMessage(MessageReceivedEvent event) { logger.warn("Detected a scam message ('{}') from user '{}' in channel '{}' of guild '{}'.", event.getMessageId(), event.getAuthor().getId(), event.getChannel().getId(), event.getGuild().getId()); } - private void deleteMessage(@NotNull MessageReceivedEvent event) { + private void deleteMessage(MessageReceivedEvent event) { event.getMessage().delete().queue(); } - private void quarantineAuthor(@NotNull MessageReceivedEvent event) { + private void quarantineAuthor(MessageReceivedEvent event) { quarantineAuthor(event.getGuild(), event.getMember(), event.getJDA().getSelfUser()); } - private void quarantineAuthor(@NotNull Guild guild, @NotNull Member author, - @NotNull SelfUser bot) { + private void quarantineAuthor(Guild guild, Member author, SelfUser bot) { String reason = "User posted scam that was automatically detected"; actionsStore.addAction(guild.getIdLong(), bot.getIdLong(), author.getIdLong(), @@ -205,7 +204,7 @@ private void quarantineAuthor(@NotNull Guild guild, @NotNull Member author, .queue(); } - private void reportScamMessage(@NotNull MessageReceivedEvent event, @NotNull String reportTitle, + private void reportScamMessage(MessageReceivedEvent event, String reportTitle, @Nullable ActionRow confirmDialog) { Guild guild = event.getGuild(); Optional reportChannel = getReportChannel(guild); @@ -231,11 +230,11 @@ private void reportScamMessage(@NotNull MessageReceivedEvent event, @NotNull Str reportChannel.orElseThrow().sendMessage(message).queue(); } - private void dmUser(@NotNull MessageReceivedEvent event) { + private void dmUser(MessageReceivedEvent event) { dmUser(event.getGuild(), event.getAuthor().getIdLong(), event.getJDA()); } - private void dmUser(@NotNull Guild guild, long userId, @NotNull JDA jda) { + private void dmUser(Guild guild, long userId, JDA jda) { String dmMessage = """ Hey there, we detected that you did send scam in the server %s and therefore put you under quarantine. @@ -251,11 +250,13 @@ If you think this was a mistake (for example, your account was hacked, but you g .queue(); } - private @NotNull Optional getReportChannel(@NotNull Guild guild) { + @Nonnull + private Optional getReportChannel(Guild guild) { return guild.getTextChannelCache().stream().filter(isReportChannel).findAny(); } - private @NotNull ActionRow createConfirmDialog(@NotNull MessageReceivedEvent event) { + @Nonnull + private ActionRow createConfirmDialog(MessageReceivedEvent event) { ComponentIdArguments args = new ComponentIdArguments(mode, event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong(), event.getAuthor().getIdLong(), @@ -265,14 +266,14 @@ If you think this was a mistake (for example, your account was hacked, but you g Button.danger(generateComponentId(args), "No")); } - private @NotNull String generateComponentId(@NotNull ComponentIdArguments args) { + @Nonnull + private String generateComponentId(ComponentIdArguments args) { return Objects.requireNonNull(componentIdGenerator) .generate(new ComponentId(getName(), args.toList()), Lifespan.REGULAR); } @Override - public void onButtonClick(@NotNull ButtonInteractionEvent event, - @NotNull List argsRaw) { + public void onButtonClick(ButtonInteractionEvent event, List argsRaw) { ComponentIdArguments args = ComponentIdArguments.fromList(argsRaw); if (event.getMember().getRoles().stream().map(Role::getName).noneMatch(hasRequiredRole)) { event.reply( @@ -334,10 +335,11 @@ public void onButtonClick(@NotNull ButtonInteractionEvent event, } - private record ComponentIdArguments(@NotNull ScamBlockerConfig.Mode mode, long guildId, - long channelId, long messageId, long authorId, @NotNull String contentHash) { + private record ComponentIdArguments(ScamBlockerConfig.Mode mode, long guildId, long channelId, + long messageId, long authorId, String contentHash) { - static @NotNull ComponentIdArguments fromList(@NotNull List args) { + @Nonnull + static ComponentIdArguments fromList(List args) { ScamBlockerConfig.Mode mode = ScamBlockerConfig.Mode.valueOf(args.get(0)); long guildId = Long.parseLong(args.get(1)); long channelId = Long.parseLong(args.get(2)); @@ -348,7 +350,7 @@ private record ComponentIdArguments(@NotNull ScamBlockerConfig.Mode mode, long g contentHash); } - @NotNull + @Nonnull List toList() { return List.of(mode.name(), Long.toString(guildId), Long.toString(channelId), Long.toString(messageId), Long.toString(authorId), contentHash); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamDetector.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamDetector.java index 15d32d15a9..d4a2281834 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamDetector.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamDetector.java @@ -1,6 +1,5 @@ package org.togetherjava.tjbot.commands.moderation.scam; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.utils.StringDistances; import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.config.ScamBlockerConfig; @@ -23,7 +22,7 @@ public final class ScamDetector { * * @param config the scam blocker config to use */ - public ScamDetector(@NotNull Config config) { + public ScamDetector(Config config) { this.config = config.getScamBlocker(); } @@ -33,20 +32,20 @@ public ScamDetector(@NotNull Config config) { * @param message the message to analyze * @return Whether the message classifies as scam */ - public boolean isScam(@NotNull CharSequence message) { + public boolean isScam(CharSequence message) { AnalyseResults results = new AnalyseResults(); TOKENIZER.splitAsStream(message).forEach(token -> analyzeToken(token, results)); return isScam(results); } - private boolean isScam(@NotNull AnalyseResults results) { + private boolean isScam(AnalyseResults results) { if (results.pingsEveryone && results.containsNitroKeyword && results.hasUrl) { return true; } return results.containsNitroKeyword && results.hasSuspiciousUrl; } - private void analyzeToken(@NotNull String token, @NotNull AnalyseResults results) { + private void analyzeToken(String token, AnalyseResults results) { if ("@everyone".equalsIgnoreCase(token)) { results.pingsEveryone = true; } @@ -60,7 +59,7 @@ private void analyzeToken(@NotNull String token, @NotNull AnalyseResults results } } - private void analyzeUrl(@NotNull String url, @NotNull AnalyseResults results) { + private void analyzeUrl(String url, AnalyseResults results) { String host; try { host = URI.create(url).getHost(); @@ -92,7 +91,7 @@ private void analyzeUrl(@NotNull String url, @NotNull AnalyseResults results) { } } - private boolean isHostSimilarToKeyword(@NotNull String host, @NotNull String keyword) { + private boolean isHostSimilarToKeyword(String host, String keyword) { // NOTE This algorithm is far from optimal. // It is good enough for our purpose though and not that complex. diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamHistoryPurgeRoutine.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamHistoryPurgeRoutine.java index 649f793b88..6c6ed71de9 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamHistoryPurgeRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamHistoryPurgeRoutine.java @@ -1,9 +1,9 @@ package org.togetherjava.tjbot.commands.moderation.scam; import net.dv8tion.jda.api.JDA; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.Routine; +import javax.annotation.Nonnull; import java.time.Instant; import java.time.Period; import java.util.concurrent.TimeUnit; @@ -20,17 +20,18 @@ public final class ScamHistoryPurgeRoutine implements Routine { * * @param scamHistoryStore containing the scam history to purge */ - public ScamHistoryPurgeRoutine(@NotNull ScamHistoryStore scamHistoryStore) { + public ScamHistoryPurgeRoutine(ScamHistoryStore scamHistoryStore) { this.scamHistoryStore = scamHistoryStore; } @Override - public @NotNull Schedule createSchedule() { + @Nonnull + public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, 1, TimeUnit.DAYS); } @Override - public void runRoutine(@NotNull JDA jda) { + public void runRoutine(JDA jda) { scamHistoryStore.deleteHistoryOlderThan(Instant.now().minus(DELETE_SCAM_RECORDS_AFTER)); } } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamHistoryStore.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamHistoryStore.java index 3154820dc5..9f1802610b 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamHistoryStore.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamHistoryStore.java @@ -1,12 +1,12 @@ package org.togetherjava.tjbot.commands.moderation.scam; import net.dv8tion.jda.api.entities.Message; -import org.jetbrains.annotations.NotNull; import org.jooq.Result; import org.togetherjava.tjbot.commands.utils.Hashing; import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.db.generated.tables.records.ScamHistoryRecord; +import javax.annotation.Nonnull; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; @@ -39,7 +39,7 @@ public final class ScamHistoryStore { * * @param database containing the scam history to work with */ - public ScamHistoryStore(@NotNull Database database) { + public ScamHistoryStore(Database database) { this.database = database; } @@ -49,7 +49,7 @@ public ScamHistoryStore(@NotNull Database database) { * @param scam the message to add * @param isDeleted whether the message is already, or about to get, deleted */ - public void addScam(@NotNull Message scam, boolean isDeleted) { + public void addScam(Message scam, boolean isDeleted) { Objects.requireNonNull(scam); database.write(context -> context.newRecord(SCAM_HISTORY) @@ -71,8 +71,8 @@ public void addScam(@NotNull Message scam, boolean isDeleted) { * @return identifications of all scam messages that have just been marked deleted, which * previously have not been marked accordingly yet */ - public @NotNull Collection markScamDuplicatesDeleted( - @NotNull Message scam) { + @Nonnull + public Collection markScamDuplicatesDeleted(Message scam) { return markScamDuplicatesDeleted(scam.getGuild().getIdLong(), scam.getAuthor().getIdLong(), hashMessageContent(scam)); } @@ -87,8 +87,9 @@ public void addScam(@NotNull Message scam, boolean isDeleted) { * @return identifications of all scam messages that have just been marked deleted, which * previously have not been marked accordingly yet */ - public @NotNull Collection markScamDuplicatesDeleted(long guildId, - long authorId, @NotNull String contentHash) { + @Nonnull + public Collection markScamDuplicatesDeleted(long guildId, long authorId, + String contentHash) { return database.writeAndProvide(context -> { Result undeletedDuplicates = context.selectFrom(SCAM_HISTORY) .where(SCAM_HISTORY.GUILD_ID.eq(guildId) @@ -111,7 +112,7 @@ public void addScam(@NotNull Message scam, boolean isDeleted) { * @param scam the scam message to look for duplicates * @return whether there are recent duplicates */ - public boolean hasRecentScamDuplicate(@NotNull Message scam) { + public boolean hasRecentScamDuplicate(Message scam) { Instant recentScamThreshold = Instant.now().minus(RECENT_SCAM_DURATION); return database.read(context -> context.fetchCount(SCAM_HISTORY, @@ -138,7 +139,8 @@ public void deleteHistoryOlderThan(Instant olderThan) { * @param message the message to hash * @return a text representation of the hash */ - public static @NotNull String hashMessageContent(@NotNull Message message) { + @Nonnull + public static String hashMessageContent(Message message) { return Hashing.bytesToHex(Hashing.hash(HASH_METHOD, message.getContentRaw().getBytes(StandardCharsets.UTF_8))); } @@ -154,8 +156,8 @@ public void deleteHistoryOlderThan(Instant olderThan) { */ public record ScamIdentification(long guildId, long channelId, long messageId, long authorId, String contentHash) { - private static ScamIdentification ofDatabaseRecord( - @NotNull ScamHistoryRecord scamHistoryRecord) { + @Nonnull + private static ScamIdentification ofDatabaseRecord(ScamHistoryRecord scamHistoryRecord) { return new ScamIdentification(scamHistoryRecord.getGuildId(), scamHistoryRecord.getChannelId(), scamHistoryRecord.getMessageId(), scamHistoryRecord.getAuthorId(), scamHistoryRecord.getContentHash()); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/package-info.java index 40b4605eff..2cf89b16e6 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/package-info.java @@ -2,4 +2,7 @@ * This package offers classes dealing with detecting scam messages and taking appropriate action, * see {@link org.togetherjava.tjbot.commands.moderation.scam.ScamBlocker} as main entry point. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.moderation.scam; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/RevocableModerationAction.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/RevocableModerationAction.java index b2cedc3007..b74290afd1 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/RevocableModerationAction.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/RevocableModerationAction.java @@ -3,9 +3,10 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.requests.RestAction; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.moderation.ModerationAction; +import javax.annotation.Nonnull; + /** * Represents revocable moderation actions, such as temporary bans. Primarily used by * {@link TemporaryModerationRoutine} to identify and revoke such actions. @@ -34,7 +35,7 @@ enum FailureIdentification { * * @return the type to apply the temporary action */ - @NotNull + @Nonnull ModerationAction getApplyType(); /** @@ -43,7 +44,7 @@ enum FailureIdentification { * * @return the type to revoke the temporary action */ - @NotNull + @Nonnull ModerationAction getRevokeType(); /** @@ -54,9 +55,8 @@ enum FailureIdentification { * @param reason why the action is revoked * @return the unsubmitted revocation action */ - @NotNull - RestAction revokeAction(@NotNull Guild guild, @NotNull User target, - @NotNull String reason); + @Nonnull + RestAction revokeAction(Guild guild, User target, String reason); /** * Handle a failure that might occur during revocation, i.e. execution of the action returned by @@ -67,6 +67,6 @@ RestAction revokeAction(@NotNull Guild guild, @NotNull User target, * @return a classification of the failure, decides whether the surrounding flow will continue * to handle the error further or not */ - @NotNull - FailureIdentification handleRevokeFailure(@NotNull Throwable failure, long targetId); + @Nonnull + FailureIdentification handleRevokeFailure(Throwable failure, long targetId); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/RevocableRoleBasedAction.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/RevocableRoleBasedAction.java index d289b00f49..bb7094f3a2 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/RevocableRoleBasedAction.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/RevocableRoleBasedAction.java @@ -1,10 +1,11 @@ package org.togetherjava.tjbot.commands.moderation.temp; import net.dv8tion.jda.api.exceptions.ErrorResponseException; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; + /** * Role based moderation actions that can be revoked, for example a {@link TemporaryMuteAction} or a * {@link TemporaryBanAction}, which are applied implicitly purely by the presence of a role. @@ -20,13 +21,13 @@ abstract class RevocableRoleBasedAction implements RevocableModerationAction { * @param actionName the action name to be used in logging in case of a failure, e.g. * {@code "mute"}, {@code "quarantine"} */ - RevocableRoleBasedAction(@NotNull String actionName) { + RevocableRoleBasedAction(String actionName) { this.actionName = actionName; } @Override - public @NotNull FailureIdentification handleRevokeFailure(@NotNull Throwable failure, - long targetId) { + @Nonnull + public FailureIdentification handleRevokeFailure(Throwable failure, long targetId) { if (failure instanceof ErrorResponseException errorResponseException) { switch (errorResponseException.getErrorResponse()) { diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryBanAction.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryBanAction.java index 0941224872..eaa42e34c9 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryBanAction.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryBanAction.java @@ -5,11 +5,12 @@ import net.dv8tion.jda.api.exceptions.ErrorResponseException; import net.dv8tion.jda.api.requests.ErrorResponse; import net.dv8tion.jda.api.requests.RestAction; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.moderation.ModerationAction; +import javax.annotation.Nonnull; + /** * Action to revoke temporary bans, as applied by * {@link org.togetherjava.tjbot.commands.moderation.BanCommand} and executed by @@ -19,24 +20,26 @@ final class TemporaryBanAction implements RevocableModerationAction { private static final Logger logger = LoggerFactory.getLogger(TemporaryBanAction.class); @Override - public @NotNull ModerationAction getApplyType() { + @Nonnull + public ModerationAction getApplyType() { return ModerationAction.BAN; } @Override - public @NotNull ModerationAction getRevokeType() { + @Nonnull + public ModerationAction getRevokeType() { return ModerationAction.UNBAN; } @Override - public @NotNull RestAction revokeAction(@NotNull Guild guild, @NotNull User target, - @NotNull String reason) { + @Nonnull + public RestAction revokeAction(Guild guild, User target, String reason) { return guild.unban(target).reason(reason); } @Override - public @NotNull FailureIdentification handleRevokeFailure(@NotNull Throwable failure, - long targetId) { + @Nonnull + public FailureIdentification handleRevokeFailure(Throwable failure, long targetId) { if (failure instanceof ErrorResponseException errorResponseException) { if (errorResponseException.getErrorResponse() == ErrorResponse.UNKNOWN_USER) { logger.debug( diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryModerationRoutine.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryModerationRoutine.java index 78e393e3b0..34df11d906 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryModerationRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryModerationRoutine.java @@ -4,7 +4,6 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.requests.RestAction; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.Routine; @@ -13,6 +12,7 @@ import org.togetherjava.tjbot.commands.moderation.ModerationActionsStore; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -43,8 +43,7 @@ public final class TemporaryModerationRoutine implements Routine { * @param actionsStore the store used to retrieve temporary moderation actions * @param config the config to use for this */ - public TemporaryModerationRoutine(@NotNull JDA jda, - @NotNull ModerationActionsStore actionsStore, @NotNull Config config) { + public TemporaryModerationRoutine(JDA jda, ModerationActionsStore actionsStore, Config config) { this.actionsStore = actionsStore; this.jda = jda; @@ -56,12 +55,13 @@ public TemporaryModerationRoutine(@NotNull JDA jda, } @Override - public void runRoutine(@NotNull JDA jda) { + public void runRoutine(JDA jda) { checkExpiredActions(); } @Override - public @NotNull Schedule createSchedule() { + @Nonnull + public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_DELAY, 5, 5, TimeUnit.MINUTES); } @@ -78,7 +78,7 @@ private void checkExpiredActions() { logger.debug("Finished checking expired temporary moderation actions to revoke."); } - private void processGroupedActions(@NotNull RevocationGroupIdentifier groupIdentifier) { + private void processGroupedActions(RevocationGroupIdentifier groupIdentifier) { // Do not revoke an action which was overwritten by a still effective action that was issued // afterwards // For example if a user was perm-banned after being temp-banned @@ -108,7 +108,7 @@ private void processGroupedActions(@NotNull RevocationGroupIdentifier groupIdent revokeAction(groupIdentifier); } - private void revokeAction(@NotNull RevocationGroupIdentifier groupIdentifier) { + private void revokeAction(RevocationGroupIdentifier groupIdentifier) { Guild guild = jda.getGuildById(groupIdentifier.guildId); if (guild == null) { logger.debug( @@ -123,8 +123,9 @@ private void revokeAction(@NotNull RevocationGroupIdentifier groupIdentifier) { }, failure -> handleFailure(failure, groupIdentifier)); } - private @NotNull RestAction executeRevocation(@NotNull Guild guild, @NotNull User target, - @NotNull ModerationAction actionType) { + @Nonnull + private RestAction executeRevocation(Guild guild, User target, + ModerationAction actionType) { logger.info("Revoked temporary action {} against user '{}' ({}).", actionType, target.getAsTag(), target.getId()); RevocableModerationAction action = getRevocableActionByType(actionType); @@ -136,8 +137,7 @@ private void revokeAction(@NotNull RevocationGroupIdentifier groupIdentifier) { return action.revokeAction(guild, target, reason); } - private void handleFailure(@NotNull Throwable failure, - @NotNull RevocationGroupIdentifier groupIdentifier) { + private void handleFailure(Throwable failure, RevocationGroupIdentifier groupIdentifier) { if (getRevocableActionByType(groupIdentifier.type).handleRevokeFailure(failure, groupIdentifier.targetId) == RevocableModerationAction.FailureIdentification.KNOWN) { return; @@ -148,15 +148,14 @@ private void handleFailure(@NotNull Throwable failure, groupIdentifier.targetId, failure); } - private @NotNull RevocableModerationAction getRevocableActionByType( - @NotNull ModerationAction type) { + @Nonnull + private RevocableModerationAction getRevocableActionByType(ModerationAction type) { return Objects.requireNonNull(typeToRevocableAction.get(type), "Action type is not revocable: " + type); } - private record RevocationGroupIdentifier(long guildId, long targetId, - @NotNull ModerationAction type) { - static RevocationGroupIdentifier of(@NotNull ActionRecord actionRecord) { + private record RevocationGroupIdentifier(long guildId, long targetId, ModerationAction type) { + static RevocationGroupIdentifier of(ActionRecord actionRecord) { return new RevocationGroupIdentifier(actionRecord.guildId(), actionRecord.targetId(), actionRecord.actionType()); } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryMuteAction.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryMuteAction.java index 921fe8b06a..94afeb2948 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryMuteAction.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryMuteAction.java @@ -3,11 +3,12 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.requests.RestAction; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.moderation.ModerationAction; import org.togetherjava.tjbot.commands.moderation.ModerationUtils; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; + /** * Action to revoke temporary mutes, as applied by * {@link org.togetherjava.tjbot.commands.moderation.MuteCommand} and executed by @@ -21,25 +22,27 @@ final class TemporaryMuteAction extends RevocableRoleBasedAction { * * @param config the config to use to identify the muted role */ - TemporaryMuteAction(@NotNull Config config) { + TemporaryMuteAction(Config config) { super("mute"); this.config = config; } @Override - public @NotNull ModerationAction getApplyType() { + @Nonnull + public ModerationAction getApplyType() { return ModerationAction.MUTE; } @Override - public @NotNull ModerationAction getRevokeType() { + @Nonnull + public ModerationAction getRevokeType() { return ModerationAction.UNMUTE; } @Override - public @NotNull RestAction revokeAction(@NotNull Guild guild, @NotNull User target, - @NotNull String reason) { + @Nonnull + public RestAction revokeAction(Guild guild, User target, String reason) { return guild .removeRoleFromMember(target.getIdLong(), ModerationUtils.getMutedRole(guild, config).orElseThrow()) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryQuarantineAction.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryQuarantineAction.java index 2e8c7908a9..67393450f3 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryQuarantineAction.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/TemporaryQuarantineAction.java @@ -3,11 +3,12 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.requests.RestAction; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.moderation.ModerationAction; import org.togetherjava.tjbot.commands.moderation.ModerationUtils; import org.togetherjava.tjbot.config.Config; +import javax.annotation.Nonnull; + /** * Action to revoke temporary quarantines, as applied by * {@link org.togetherjava.tjbot.commands.moderation.QuarantineCommand} and executed by @@ -21,25 +22,27 @@ final class TemporaryQuarantineAction extends RevocableRoleBasedAction { * * @param config the config to use to identify the quarantined role */ - TemporaryQuarantineAction(@NotNull Config config) { + TemporaryQuarantineAction(Config config) { super("quarantine"); this.config = config; } @Override - public @NotNull ModerationAction getApplyType() { + @Nonnull + public ModerationAction getApplyType() { return ModerationAction.QUARANTINE; } @Override - public @NotNull ModerationAction getRevokeType() { + @Nonnull + public ModerationAction getRevokeType() { return ModerationAction.UNQUARANTINE; } @Override - public @NotNull RestAction revokeAction(@NotNull Guild guild, @NotNull User target, - @NotNull String reason) { + @Nonnull + public RestAction revokeAction(Guild guild, User target, String reason) { return guild .removeRoleFromMember(target.getIdLong(), ModerationUtils.getQuarantinedRole(guild, config).orElseThrow()) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/package-info.java index ba0fe1bbe9..6a11e771d2 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/temp/package-info.java @@ -1,4 +1,7 @@ /** * This package offers classes dealing with temporary moderation actions, such as temporary bans. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.moderation.temp; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/package-info.java index 17e5e3366c..0a00d8bf03 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/package-info.java @@ -9,4 +9,7 @@ * {@link org.togetherjava.tjbot.commands.SlashCommand} or using the adapter * {@link org.togetherjava.tjbot.commands.SlashCommandAdapter} for convenience. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/reminder/RemindCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/reminder/RemindCommand.java index ef1128f035..513e72438a 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/reminder/RemindCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/reminder/RemindCommand.java @@ -7,11 +7,11 @@ import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; -import org.jetbrains.annotations.NotNull; import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.db.Database; +import javax.annotation.Nonnull; import java.time.*; import java.time.temporal.TemporalAmount; import java.util.List; @@ -52,7 +52,7 @@ public final class RemindCommand extends SlashCommandAdapter { * * @param database to store and fetch the reminders from */ - public RemindCommand(@NotNull Database database) { + public RemindCommand(Database database) { super(COMMAND_NAME, "Reminds you after a given time period has passed (e.g. in 5 weeks)", SlashCommandVisibility.GUILD); @@ -72,7 +72,7 @@ public RemindCommand(@NotNull Database database) { } @Override - public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommand(SlashCommandInteractionEvent event) { int timeAmount = Math.toIntExact(event.getOption(TIME_AMOUNT_OPTION).getAsLong()); String timeUnit = event.getOption(TIME_UNIT_OPTION).getAsString(); String content = event.getOption(CONTENT_OPTION).getAsString(); @@ -102,7 +102,8 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { .insert()); } - private static @NotNull Instant parseWhen(int whenAmount, @NotNull String whenUnit) { + @Nonnull + private static Instant parseWhen(int whenAmount, String whenUnit) { TemporalAmount period = switch (whenUnit) { case "second", "seconds" -> Duration.ofSeconds(whenAmount); case "minute", "minutes" -> Duration.ofMinutes(whenAmount); @@ -117,8 +118,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) { return ZonedDateTime.now(ZoneOffset.UTC).plus(period).toInstant(); } - private static boolean handleIsRemindAtWithinLimits(@NotNull Instant remindAt, - @NotNull IReplyCallback event) { + private static boolean handleIsRemindAtWithinLimits(Instant remindAt, IReplyCallback event) { ZonedDateTime maxWhen = ZonedDateTime.now(ZoneOffset.UTC).plus(MAX_TIME_PERIOD); if (remindAt.atZone(ZoneOffset.UTC).isBefore(maxWhen)) { @@ -134,8 +134,8 @@ private static boolean handleIsRemindAtWithinLimits(@NotNull Instant remindAt, return false; } - private boolean handleIsUserBelowMaxPendingReminders(@NotNull ISnowflake author, - @NotNull ISnowflake guild, @NotNull IReplyCallback event) { + private boolean handleIsUserBelowMaxPendingReminders(ISnowflake author, ISnowflake guild, + IReplyCallback event) { int pendingReminders = database.read(context -> context.fetchCount(PENDING_REMINDERS, PENDING_REMINDERS.AUTHOR_ID.equal(author.getIdLong()) .and(PENDING_REMINDERS.GUILD_ID.equal(guild.getIdLong())))); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/reminder/RemindRoutine.java b/application/src/main/java/org/togetherjava/tjbot/commands/reminder/RemindRoutine.java index 563231afb3..c755fe0974 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/reminder/RemindRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/reminder/RemindRoutine.java @@ -2,17 +2,20 @@ import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.entities.*; +import net.dv8tion.jda.api.entities.MessageChannel; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.PrivateChannel; +import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.MessageAction; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.Routine; import org.togetherjava.tjbot.db.Database; -import java.awt.*; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.awt.Color; import java.time.Instant; import java.time.temporal.TemporalAccessor; import java.util.concurrent.TimeUnit; @@ -37,18 +40,19 @@ public final class RemindRoutine implements Routine { * * @param database the database that contains the pending reminders to send. */ - public RemindRoutine(@NotNull Database database) { + public RemindRoutine(Database database) { this.database = database; } @Override - public @NotNull Schedule createSchedule() { + @Nonnull + public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, SCHEDULE_INTERVAL_SECONDS, TimeUnit.SECONDS); } @Override - public void runRoutine(@NotNull JDA jda) { + public void runRoutine(JDA jda) { Instant now = Instant.now(); database.write(context -> context.selectFrom(PENDING_REMINDERS) .where(PENDING_REMINDERS.REMIND_AT.lessOrEqual(now)) @@ -62,13 +66,13 @@ public void runRoutine(@NotNull JDA jda) { })); } - private static void sendReminder(@NotNull JDA jda, long id, long channelId, long authorId, - @NotNull CharSequence content, @NotNull TemporalAccessor createdAt) { + private static void sendReminder(JDA jda, long id, long channelId, long authorId, + CharSequence content, TemporalAccessor createdAt) { RestAction route = computeReminderRoute(jda, channelId, authorId); sendReminderViaRoute(route, id, content, createdAt); } - private static RestAction computeReminderRoute(@NotNull JDA jda, long channelId, + private static RestAction computeReminderRoute(JDA jda, long channelId, long authorId) { // If guild channel can still be found, send there MessageChannel channel = jda.getChannelById(MessageChannel.class, channelId); @@ -80,20 +84,21 @@ private static RestAction computeReminderRoute(@NotNull JDA jda, return createDmReminderRoute(jda, authorId); } - private static @NotNull RestAction createGuildReminderRoute(@NotNull JDA jda, - long authorId, @NotNull MessageChannel channel) { + @Nonnull + private static RestAction createGuildReminderRoute(JDA jda, long authorId, + MessageChannel channel) { return jda.retrieveUserById(authorId) .onErrorMap(error -> null) .map(author -> ReminderRoute.toPublic(channel, author)); } - private static @NotNull RestAction createDmReminderRoute(@NotNull JDA jda, - long authorId) { + @Nonnull + private static RestAction createDmReminderRoute(JDA jda, long authorId) { return jda.openPrivateChannelById(authorId).map(ReminderRoute::toPrivate); } - private static void sendReminderViaRoute(@NotNull RestAction routeAction, - long id, @NotNull CharSequence content, @NotNull TemporalAccessor createdAt) { + private static void sendReminderViaRoute(RestAction routeAction, long id, + CharSequence content, TemporalAccessor createdAt) { Function sendMessage = route -> route.channel .sendMessageEmbeds(createReminderEmbed(content, createdAt, route.target())) .content(route.description()); @@ -108,8 +113,9 @@ Failed to send a reminder (id '{}'), skipping it. This can be due to a network i routeAction.flatMap(sendMessage).queue(doNothing(), logFailure); } - private static @NotNull MessageEmbed createReminderEmbed(@NotNull CharSequence content, - @NotNull TemporalAccessor createdAt, @Nullable User author) { + @Nonnull + private static MessageEmbed createReminderEmbed(CharSequence content, + TemporalAccessor createdAt, @Nullable User author) { String authorName = author == null ? "Unknown user" : author.getAsTag(); String authorIconUrl = author == null ? null : author.getAvatarUrl(); @@ -121,19 +127,22 @@ Failed to send a reminder (id '{}'), skipping it. This can be due to a network i .build(); } - private static @NotNull Consumer doNothing() { + @Nonnull + private static Consumer doNothing() { return a -> { }; } - private record ReminderRoute(@NotNull MessageChannel channel, @Nullable User target, + private record ReminderRoute(MessageChannel channel, @Nullable User target, @Nullable String description) { - static ReminderRoute toPublic(@NotNull MessageChannel channel, @Nullable User target) { + @Nonnull + static ReminderRoute toPublic(MessageChannel channel, @Nullable User target) { return new ReminderRoute(channel, target, target == null ? null : target.getAsMention()); } - static ReminderRoute toPrivate(@NotNull PrivateChannel channel) { + @Nonnull + static ReminderRoute toPrivate(PrivateChannel channel) { return new ReminderRoute(channel, channel.getUser(), "(Sending your reminder directly, because I was unable to locate" + " the original channel you wanted it to be send to)"); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/reminder/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/reminder/package-info.java index a7f65b1c69..f4fab40923 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/reminder/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/reminder/package-info.java @@ -2,4 +2,7 @@ * This packages offers all the functionality for the remind-command. The core class is * {@link org.togetherjava.tjbot.commands.reminder.RemindCommand}. */ +@ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.reminder; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java b/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java index 5921a542fc..f7eae74609 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/system/BotCore.java @@ -15,7 +15,6 @@ import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.components.ComponentInteraction; import net.dv8tion.jda.api.requests.ErrorResponse; -import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.commands.*; @@ -26,6 +25,7 @@ import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.db.Database; +import javax.annotation.Nonnull; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -71,8 +71,7 @@ public final class BotCore extends ListenerAdapter implements SlashCommandProvid * @param database the database that commands may use to persist data * @param config the configuration to use for this system */ - @SuppressWarnings("ThisEscapedInObjectConstruction") - public BotCore(@NotNull JDA jda, @NotNull Database database, @NotNull Config config) { + public BotCore(JDA jda, Database database, Config config) { this.config = config; Collection features = Features.createFeatures(jda, database, config); @@ -126,7 +125,8 @@ public BotCore(@NotNull JDA jda, @NotNull Database database, @NotNull Config con } @Override - public @NotNull Collection getSlashCommands() { + @Nonnull + public Collection getSlashCommands() { return nameToInteractor.values() .stream() .filter(SlashCommand.class::isInstance) @@ -135,7 +135,8 @@ public BotCore(@NotNull JDA jda, @NotNull Database database, @NotNull Config con } @Override - public @NotNull Optional getSlashCommand(@NotNull String name) { + @Nonnull + public Optional getSlashCommand(String name) { return Optional.ofNullable(nameToInteractor.get(name)) .filter(SlashCommand.class::isInstance) .map(SlashCommand.class::cast); @@ -146,7 +147,7 @@ public BotCore(@NotNull JDA jda, @NotNull Database database, @NotNull Config con * * @param jda the JDA instance to work with */ - public void onReady(@NotNull JDA jda) { + public void onReady(JDA jda) { if (!receivedOnReady.compareAndSet(false, true)) { // Ensures that we only enter the event once return; @@ -163,7 +164,7 @@ public void onReady(@NotNull JDA jda) { scheduleRoutines(jda); } - private void scheduleRoutines(@NotNull JDA jda) { + private void scheduleRoutines(JDA jda) { routines.forEach(routine -> { Runnable command = () -> { String routineName = routine.getClass().getSimpleName(); @@ -188,7 +189,7 @@ private void scheduleRoutines(@NotNull JDA jda) { } @Override - public void onMessageReceived(@NotNull final MessageReceivedEvent event) { + public void onMessageReceived(final MessageReceivedEvent event) { if (event.isFromGuild()) { getMessageReceiversSubscribedTo(event.getChannel()) .forEach(messageReceiver -> messageReceiver.onMessageReceived(event)); @@ -196,15 +197,15 @@ public void onMessageReceived(@NotNull final MessageReceivedEvent event) { } @Override - public void onMessageUpdate(@NotNull final MessageUpdateEvent event) { + public void onMessageUpdate(final MessageUpdateEvent event) { if (event.isFromGuild()) { getMessageReceiversSubscribedTo(event.getChannel()) .forEach(messageReceiver -> messageReceiver.onMessageUpdated(event)); } } - private @NotNull Stream getMessageReceiversSubscribedTo( - @NotNull Channel channel) { + @Nonnull + private Stream getMessageReceiversSubscribedTo(Channel channel) { String channelName = channel.getName(); return channelNameToMessageReceiver.entrySet() .stream() @@ -215,14 +216,14 @@ public void onMessageUpdate(@NotNull final MessageUpdateEvent event) { } @Override - public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { + public void onSlashCommandInteraction(SlashCommandInteractionEvent event) { logger.debug("Received slash command '{}' (#{}) on guild '{}'", event.getName(), event.getId(), event.getGuild()); COMMAND_SERVICE.execute(() -> requireSlashCommand(event.getName()).onSlashCommand(event)); } @Override - public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { + public void onButtonInteraction(ButtonInteractionEvent event) { logger.debug("Received button click '{}' (#{}) on guild '{}'", event.getComponentId(), event.getId(), event.getGuild()); COMMAND_SERVICE @@ -230,14 +231,14 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { } @Override - public void onSelectMenuInteraction(@NotNull SelectMenuInteractionEvent event) { + public void onSelectMenuInteraction(SelectMenuInteractionEvent event) { logger.debug("Received selection menu event '{}' (#{}) on guild '{}'", event.getComponentId(), event.getId(), event.getGuild()); COMMAND_SERVICE .execute(() -> forwardComponentCommand(event, UserInteractor::onSelectionMenu)); } - private void registerReloadCommand(@NotNull Guild guild) { + private void registerReloadCommand(Guild guild) { guild.retrieveCommands().queue(commands -> { // Has it been registered already? if (commands.stream().map(Command::getName).anyMatch(RELOAD_COMMAND::equals)) { @@ -257,7 +258,6 @@ private void registerReloadCommand(@NotNull Guild guild) { /** * Forwards the given component event to the associated user interactor. *

- *

* An example call might look like: * *

@@ -271,8 +271,8 @@ private void registerReloadCommand(@NotNull Guild guild) {
      *        providing the event and list of arguments for consumption
      * @param  the type of the component interaction that should be forwarded
      */
-    private  void forwardComponentCommand(@NotNull T event,
-            @NotNull TriConsumer> interactorArgumentConsumer) {
+    private  void forwardComponentCommand(T event,
+            TriConsumer> interactorArgumentConsumer) {
         Optional componentIdOpt;
         try {
             componentIdOpt = componentIdParser.parse(event.getComponentId());
@@ -308,7 +308,8 @@ private  void forwardComponentCommand(@NotNull T
      * @return the command with the given name
      * @throws NullPointerException if the command with the given name was not registered
      */
-    private @NotNull SlashCommand requireSlashCommand(@NotNull String name) {
+    @Nonnull
+    private SlashCommand requireSlashCommand(String name) {
         return getSlashCommand(name).orElseThrow(
                 () -> new NullPointerException("There is no slash command with name " + name));
     }
@@ -320,7 +321,8 @@ private  void forwardComponentCommand(@NotNull T
      * @return the user interactor with the given name
      * @throws NullPointerException if the user interactor with the given name was not registered
      */
-    private @NotNull UserInteractor requireUserInteractor(@NotNull String name) {
+    @Nonnull
+    private UserInteractor requireUserInteractor(String name) {
         return Objects.requireNonNull(nameToInteractor.get(name));
     }
 
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/system/LogLevelCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/system/LogLevelCommand.java
index 32a66f41b4..2780f3f8ed 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/system/LogLevelCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/system/LogLevelCommand.java
@@ -6,7 +6,6 @@
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.config.Configurator;
-import org.jetbrains.annotations.NotNull;
 import org.togetherjava.tjbot.commands.SlashCommandAdapter;
 import org.togetherjava.tjbot.commands.SlashCommandVisibility;
 
@@ -44,7 +43,7 @@ public LogLevelCommand() {
     // Security warning about changing log configs. We only change the level, that is safe.
     @SuppressWarnings("squid:S4792")
     @Override
-    public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
+    public void onSlashCommand(SlashCommandInteractionEvent event) {
         String levelText = event.getOption(LOG_LEVEL_OPTION).getAsString();
         Level level = Level.getLevel(levelText);
 
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/system/ReloadCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/system/ReloadCommand.java
index 256faa7d5e..1b715aad28 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/system/ReloadCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/system/ReloadCommand.java
@@ -10,7 +10,6 @@
 import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
 import net.dv8tion.jda.api.requests.RestAction;
 import net.dv8tion.jda.api.requests.restaction.CommandListUpdateAction;
-import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.togetherjava.tjbot.commands.SlashCommand;
@@ -18,6 +17,7 @@
 import org.togetherjava.tjbot.commands.SlashCommandVisibility;
 import org.togetherjava.tjbot.commands.utils.MessageUtils;
 
+import javax.annotation.Nonnull;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -46,7 +46,7 @@ public final class ReloadCommand extends SlashCommandAdapter {
      * @param commandProvider the provider of slash commands to reload when this command is
      *        triggered
      */
-    public ReloadCommand(@NotNull SlashCommandProvider commandProvider) {
+    public ReloadCommand(SlashCommandProvider commandProvider) {
         super("reload",
                 "Uploads all existing slash-commands to Discord so they are fully up-to-date.",
                 SlashCommandVisibility.GUILD);
@@ -54,7 +54,7 @@ public ReloadCommand(@NotNull SlashCommandProvider commandProvider) {
     }
 
     @Override
-    public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
+    public void onSlashCommand(SlashCommandInteractionEvent event) {
         Member member = Objects.requireNonNull(event.getMember());
 
         if (!member.hasPermission(Permission.MANAGE_SERVER)) {
@@ -75,7 +75,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
     }
 
     @Override
-    public void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List args) {
+    public void onButtonClick(ButtonInteractionEvent event, List args) {
         // Ignore if another user clicked the button
         String userId = args.get(0);
         if (!userId.equals(Objects.requireNonNull(event.getMember()).getId())) {
@@ -102,8 +102,7 @@ public void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List updateCommandsIf(
@@ -133,9 +132,9 @@ public void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List commandFilter,
-            @NotNull CommandListUpdateAction updateAction) {
+    @Nonnull
+    private CommandListUpdateAction updateCommandsIf(Predicate commandFilter,
+            CommandListUpdateAction updateAction) {
         return commandProvider.getSlashCommands()
             .stream()
             .filter(commandFilter)
@@ -143,12 +142,13 @@ public void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List x);
     }
 
-    private static @NotNull CommandListUpdateAction getGlobalUpdateAction(@NotNull JDA jda) {
+    @Nonnull
+    private static CommandListUpdateAction getGlobalUpdateAction(JDA jda) {
         return jda.updateCommands();
     }
 
-    private static @NotNull Stream getGuildUpdateActions(
-            @NotNull JDA jda) {
+    @Nonnull
+    private static Stream getGuildUpdateActions(JDA jda) {
         return jda.getGuildCache().stream().map(Guild::updateCommands);
     }
 }
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/system/SlashCommandProvider.java b/application/src/main/java/org/togetherjava/tjbot/commands/system/SlashCommandProvider.java
index ef9f0357bd..85cc662511 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/system/SlashCommandProvider.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/system/SlashCommandProvider.java
@@ -1,8 +1,8 @@
 package org.togetherjava.tjbot.commands.system;
 
-import org.jetbrains.annotations.NotNull;
 import org.togetherjava.tjbot.commands.SlashCommand;
 
+import javax.annotation.Nonnull;
 import java.util.Collection;
 import java.util.Optional;
 
@@ -15,7 +15,7 @@ public interface SlashCommandProvider {
      *
      * @return all slash commands
      */
-    @NotNull
+    @Nonnull
     Collection getSlashCommands();
 
     /**
@@ -24,6 +24,6 @@ public interface SlashCommandProvider {
      * @param name the name of the command
      * @return the command registered under this name, if any
      */
-    @NotNull
-    Optional getSlashCommand(@NotNull String name);
+    @Nonnull
+    Optional getSlashCommand(String name);
 }
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/system/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/system/package-info.java
index 60670e1341..48e796b587 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/system/package-info.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/system/package-info.java
@@ -2,4 +2,7 @@
  * This package represents the core of the command system. The entry point is
  * {@link org.togetherjava.tjbot.commands.system.BotCore}.
  */
+@ParametersAreNonnullByDefault
 package org.togetherjava.tjbot.commands.system;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java
index de59fae319..615ee799ae 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagCommand.java
@@ -5,7 +5,6 @@
 import net.dv8tion.jda.api.interactions.commands.OptionMapping;
 import net.dv8tion.jda.api.interactions.commands.OptionType;
 import net.dv8tion.jda.api.requests.restaction.interactions.ReplyCallbackAction;
-import org.jetbrains.annotations.NotNull;
 import org.togetherjava.tjbot.commands.SlashCommandAdapter;
 import org.togetherjava.tjbot.commands.SlashCommandVisibility;
 
@@ -43,7 +42,7 @@ public TagCommand(TagSystem tagSystem) {
     }
 
     @Override
-    public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
+    public void onSlashCommand(SlashCommandInteractionEvent event) {
         String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString();
         OptionMapping replyToUserOption = event.getOption(REPLY_TO_USER_OPTION);
 
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java
index 3cebad8f10..9b34c08a12 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagManageCommand.java
@@ -10,21 +10,18 @@
 import net.dv8tion.jda.api.interactions.commands.OptionType;
 import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
 import net.dv8tion.jda.api.requests.ErrorResponse;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.togetherjava.tjbot.commands.SlashCommandAdapter;
 import org.togetherjava.tjbot.commands.SlashCommandVisibility;
 import org.togetherjava.tjbot.moderation.ModAuditLogWriter;
 
-import java.time.temporal.TemporalAccessor;
-import java.util.*;
-import java.util.NoSuchElementException;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import java.nio.charset.StandardCharsets;
 import java.time.Instant;
-import java.util.Objects;
-import java.util.OptionalLong;
+import java.time.temporal.TemporalAccessor;
+import java.util.*;
 import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
@@ -71,8 +68,7 @@ public final class TagManageCommand extends SlashCommandAdapter {
      * @param tagSystem the system providing the actual tag data
      * @param modAuditLogWriter to log tag changes for audition
      */
-    public TagManageCommand(@NotNull TagSystem tagSystem,
-            @NotNull ModAuditLogWriter modAuditLogWriter) {
+    public TagManageCommand(TagSystem tagSystem, ModAuditLogWriter modAuditLogWriter) {
         super("tag-manage", "Provides commands to manage all tags", SlashCommandVisibility.GUILD);
 
         this.tagSystem = tagSystem;
@@ -104,8 +100,7 @@ public TagManageCommand(@NotNull TagSystem tagSystem,
                     .addOption(OptionType.STRING, ID_OPTION, ID_DESCRIPTION, true));
     }
 
-    private static void sendSuccessMessage(@NotNull IReplyCallback event, @NotNull String id,
-            @NotNull String actionVerb) {
+    private static void sendSuccessMessage(IReplyCallback event, String id, String actionVerb) {
         logger.info("User '{}' {} the tag with id '{}'.", event.getUser().getId(), actionVerb, id);
 
         event
@@ -128,8 +123,8 @@ private static void sendSuccessMessage(@NotNull IReplyCallback event, @NotNull S
      * @param event the event to send messages with
      * @return the parsed message id, if successful
      */
-    private static OptionalLong parseMessageIdAndHandle(@NotNull String messageId,
-            @NotNull IReplyCallback event) {
+    @Nonnull
+    private static OptionalLong parseMessageIdAndHandle(String messageId, IReplyCallback event) {
         try {
             return OptionalLong.of(Long.parseLong(messageId));
         } catch (NumberFormatException e) {
@@ -143,7 +138,7 @@ private static OptionalLong parseMessageIdAndHandle(@NotNull String messageId,
     }
 
     @Override
-    public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
+    public void onSlashCommand(SlashCommandInteractionEvent event) {
         switch (Subcommand.fromName(event.getSubcommandName())) {
             case RAW -> rawTag(event);
             case CREATE -> createTag(event);
@@ -156,7 +151,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
         }
     }
 
-    private void rawTag(@NotNull SlashCommandInteractionEvent event) {
+    private void rawTag(SlashCommandInteractionEvent event) {
         String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString();
         if (tagSystem.handleIsUnknownTag(id, event)) {
             return;
@@ -168,31 +163,31 @@ private void rawTag(@NotNull SlashCommandInteractionEvent event) {
             .queue();
     }
 
-    private void createTag(@NotNull CommandInteraction event) {
+    private void createTag(CommandInteraction event) {
         String content = Objects.requireNonNull(event.getOption(CONTENT_OPTION)).getAsString();
 
         handleAction(TagStatus.NOT_EXISTS, id -> tagSystem.putTag(id, content), event,
                 Subcommand.CREATE, content);
     }
 
-    private void createTagWithMessage(@NotNull CommandInteraction event) {
+    private void createTagWithMessage(CommandInteraction event) {
         handleActionWithMessage(TagStatus.NOT_EXISTS, tagSystem::putTag, event,
                 Subcommand.CREATE_WITH_MESSAGE);
     }
 
-    private void editTag(@NotNull CommandInteraction event) {
+    private void editTag(CommandInteraction event) {
         String content = Objects.requireNonNull(event.getOption(CONTENT_OPTION)).getAsString();
 
         handleAction(TagStatus.EXISTS, id -> tagSystem.putTag(id, content), event, Subcommand.EDIT,
                 content);
     }
 
-    private void editTagWithMessage(@NotNull CommandInteraction event) {
+    private void editTagWithMessage(CommandInteraction event) {
         handleActionWithMessage(TagStatus.EXISTS, tagSystem::putTag, event,
                 Subcommand.EDIT_WITH_MESSAGE);
     }
 
-    private void deleteTag(@NotNull CommandInteraction event) {
+    private void deleteTag(CommandInteraction event) {
         handleAction(TagStatus.EXISTS, tagSystem::deleteTag, event, Subcommand.DELETE, null);
     }
 
@@ -208,9 +203,8 @@ private void deleteTag(@NotNull CommandInteraction event) {
      * @param subcommand the subcommand to be executed
      * @param newContent the new content of the tag, or null if content is unchanged
      */
-    private void handleAction(@NotNull TagStatus requiredTagStatus,
-            @NotNull Consumer idAction, @NotNull CommandInteraction event,
-            @NotNull Subcommand subcommand, @Nullable String newContent) {
+    private void handleAction(TagStatus requiredTagStatus, Consumer idAction,
+            CommandInteraction event, Subcommand subcommand, @Nullable String newContent) {
 
         String id = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString();
         if (isWrongTagStatusAndHandle(requiredTagStatus, id, event)) {
@@ -243,9 +237,9 @@ private void handleAction(@NotNull TagStatus requiredTagStatus,
      *        {@code message-id} option set
      * @param subcommand the subcommand to be executed
      */
-    private void handleActionWithMessage(@NotNull TagStatus requiredTagStatus,
-            @NotNull BiConsumer idAndContentAction,
-            @NotNull CommandInteraction event, @NotNull Subcommand subcommand) {
+    private void handleActionWithMessage(TagStatus requiredTagStatus,
+            BiConsumer idAndContentAction, CommandInteraction event,
+            Subcommand subcommand) {
 
         String tagId = Objects.requireNonNull(event.getOption(ID_OPTION)).getAsString();
         OptionalLong messageIdOpt = parseMessageIdAndHandle(
@@ -295,8 +289,8 @@ private void handleActionWithMessage(@NotNull TagStatus requiredTagStatus,
      * @param id the id of the tag to get its content
      * @return the content of the tag, if present
      */
-    private @NotNull Optional getTagContent(@NotNull Subcommand subcommand,
-            @NotNull String id) {
+    @Nonnull
+    private Optional getTagContent(Subcommand subcommand, String id) {
         if (Subcommand.SUBCOMMANDS_WITH_PREVIOUS_CONTENT.contains(subcommand)) {
             try {
                 return tagSystem.getTag(id);
@@ -322,8 +316,8 @@ private void handleActionWithMessage(@NotNull TagStatus requiredTagStatus,
      * @param event the event to send messages with
      * @return whether the status of the given tag is not equal to the required status
      */
-    private boolean isWrongTagStatusAndHandle(@NotNull TagStatus requiredTagStatus,
-            @NotNull String id, @NotNull IReplyCallback event) {
+    private boolean isWrongTagStatusAndHandle(TagStatus requiredTagStatus, String id,
+            IReplyCallback event) {
         if (requiredTagStatus == TagStatus.EXISTS) {
             return tagSystem.handleIsUnknownTag(id, event);
         } else if (requiredTagStatus == TagStatus.NOT_EXISTS) {
@@ -339,9 +333,9 @@ private boolean isWrongTagStatusAndHandle(@NotNull TagStatus requiredTagStatus,
         return false;
     }
 
-    private void logAction(@NotNull Subcommand subcommand, @NotNull Guild guild,
-            @NotNull User author, @NotNull TemporalAccessor triggeredAt, @NotNull String id,
-            @Nullable String newContent, @Nullable String previousContent) {
+    private void logAction(Subcommand subcommand, Guild guild, User author,
+            TemporalAccessor triggeredAt, String id, @Nullable String newContent,
+            @Nullable String previousContent) {
 
         List attachments = new ArrayList<>();
 
@@ -407,17 +401,18 @@ enum Subcommand {
         private final String name;
         private final String actionVerb;
 
-        Subcommand(@NotNull String name, @NotNull String actionVerb) {
+        Subcommand(String name, String actionVerb) {
             this.name = name;
             this.actionVerb = actionVerb;
         }
 
-        @NotNull
+        @Nonnull
         String getName() {
             return name;
         }
 
-        static Subcommand fromName(@NotNull String name) {
+        @Nonnull
+        static Subcommand fromName(String name) {
             for (Subcommand subcommand : Subcommand.values()) {
                 if (subcommand.name.equals(name)) {
                     return subcommand;
@@ -427,7 +422,7 @@ static Subcommand fromName(@NotNull String name) {
                     "Subcommand with name '%s' is unknown".formatted(name));
         }
 
-        @NotNull
+        @Nonnull
         String getActionVerb() {
             return actionVerb;
         }
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java
index 0a9090d0d5..13272b6131 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagSystem.java
@@ -4,13 +4,13 @@
 import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback;
 import net.dv8tion.jda.api.interactions.components.buttons.Button;
 import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
-import org.jetbrains.annotations.NotNull;
 import org.togetherjava.tjbot.commands.utils.StringDistances;
 import org.togetherjava.tjbot.db.Database;
 import org.togetherjava.tjbot.db.generated.tables.Tags;
 import org.togetherjava.tjbot.db.generated.tables.records.TagsRecord;
 
-import java.awt.*;
+import javax.annotation.Nonnull;
+import java.awt.Color;
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -58,8 +58,7 @@ static Button createDeleteButton(String componentId) {
      * @param event the event to send messages with
      * @return whether the given tag is unknown to the system
      */
-    @SuppressWarnings("BooleanMethodNameMustStartWithQuestion")
-    boolean handleIsUnknownTag(@NotNull String id, @NotNull IReplyCallback event) {
+    boolean handleIsUnknownTag(String id, IReplyCallback event) {
         if (hasTag(id)) {
             return false;
         }
@@ -123,6 +122,7 @@ void putTag(String id, String content) {
      * @param id the id of the tag to get
      * @return the content of the tag, if the tag is known to the system
      */
+    @Nonnull
     Optional getTag(String id) {
         return database.readTransaction(context -> Optional
             .ofNullable(context.selectFrom(Tags.TAGS).where(Tags.TAGS.ID.eq(id)).fetchOne())
@@ -134,6 +134,7 @@ Optional getTag(String id) {
      *
      * @return a set of all ids known to the system, not backed
      */
+    @Nonnull
     Set getAllIds() {
         return database.readTransaction(context -> context.select(Tags.TAGS.ID)
             .from(Tags.TAGS)
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagsCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagsCommand.java
index 8606c7f933..3432720cb9 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagsCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/TagsCommand.java
@@ -4,7 +4,6 @@
 import net.dv8tion.jda.api.Permission;
 import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
 import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
-import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.togetherjava.tjbot.commands.SlashCommandAdapter;
@@ -49,7 +48,7 @@ public TagsCommand(TagSystem tagSystem) {
     }
 
     @Override
-    public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
+    public void onSlashCommand(SlashCommandInteractionEvent event) {
         Collection tagIds = tagSystem.getAllIds();
         if (tagIds.size() > MAX_TAGS_THRESHOLD_WARNING) {
             // TODO Implement the edge case
@@ -73,7 +72,7 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
     }
 
     @Override
-    public void onButtonClick(@NotNull ButtonInteractionEvent event, @NotNull List args) {
+    public void onButtonClick(ButtonInteractionEvent event, List args) {
         String userId = args.get(0);
 
         if (!event.getUser().getId().equals(userId) && !Objects.requireNonNull(event.getMember())
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tags/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/package-info.java
index e250c06ae9..41eb96651e 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tags/package-info.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tags/package-info.java
@@ -4,4 +4,7 @@
  * like {@link org.togetherjava.tjbot.commands.tags.TagCommand} as entry point to the package's
  * offered functionality.
  */
+@ParametersAreNonnullByDefault
 package org.togetherjava.tjbot.commands.tags;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersCommand.java b/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersCommand.java
index f7f6a44e4f..5556384cfe 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersCommand.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersCommand.java
@@ -10,8 +10,6 @@
 import net.dv8tion.jda.api.interactions.commands.OptionMapping;
 import net.dv8tion.jda.api.interactions.commands.OptionType;
 import net.dv8tion.jda.api.interactions.commands.build.OptionData;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 import org.jooq.Records;
 import org.jooq.impl.DSL;
 import org.slf4j.Logger;
@@ -20,6 +18,8 @@
 import org.togetherjava.tjbot.commands.SlashCommandVisibility;
 import org.togetherjava.tjbot.db.Database;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import java.math.BigDecimal;
 import java.time.*;
 import java.time.format.TextStyle;
@@ -50,7 +50,7 @@ public final class TopHelpersCommand extends SlashCommandAdapter {
      *
      * @param database the database containing the message records of top helpers
      */
-    public TopHelpersCommand(@NotNull Database database) {
+    public TopHelpersCommand(Database database) {
         super(COMMAND_NAME, "Lists top helpers for the last month, or a given month",
                 SlashCommandVisibility.GUILD);
 
@@ -65,7 +65,7 @@ public TopHelpersCommand(@NotNull Database database) {
     }
 
     @Override
-    public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
+    public void onSlashCommand(SlashCommandInteractionEvent event) {
         OptionMapping atMonthData = event.getOption(MONTH_OPTION);
 
         TimeRange timeRange = computeTimeRange(computeMonth(atMonthData));
@@ -88,7 +88,8 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
             .onSuccess(members -> handleTopHelpers(topHelpers, members, timeRange, event));
     }
 
-    private static @NotNull Month computeMonth(@Nullable OptionMapping atMonthData) {
+    @Nonnull
+    private static Month computeMonth(@Nullable OptionMapping atMonthData) {
         if (atMonthData != null) {
             return Month.valueOf(atMonthData.getAsString());
         }
@@ -97,7 +98,8 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
         return Instant.now().atZone(ZoneOffset.UTC).minusMonths(1).getMonth();
     }
 
-    private static @NotNull TimeRange computeTimeRange(@NotNull Month atMonth) {
+    @Nonnull
+    private static TimeRange computeTimeRange(Month atMonth) {
         ZonedDateTime now = Instant.now().atZone(ZoneOffset.UTC);
 
         int atYear = now.getYear();
@@ -115,8 +117,8 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
         return new TimeRange(start, end, description);
     }
 
-    private @NotNull List computeTopHelpersDescending(long guildId,
-            @NotNull TimeRange timeRange) {
+    @Nonnull
+    private List computeTopHelpersDescending(long guildId, TimeRange timeRange) {
         return database.read(context -> context
             .select(HELP_CHANNEL_MESSAGES.AUTHOR_ID, DSL.sum(HELP_CHANNEL_MESSAGES.MESSAGE_LENGTH))
             .from(HELP_CHANNEL_MESSAGES)
@@ -128,14 +130,13 @@ public void onSlashCommand(@NotNull SlashCommandInteractionEvent event) {
             .fetch(Records.mapping(TopHelperResult::new)));
     }
 
-    private static void handleError(@NotNull Throwable error, @NotNull IDeferrableCallback event) {
+    private static void handleError(Throwable error, IDeferrableCallback event) {
         logger.warn("Failed to compute top-helpers", error);
         event.getHook().editOriginal("Sorry, something went wrong.").queue();
     }
 
-    private static void handleTopHelpers(@NotNull Collection topHelpers,
-            @NotNull Collection members, @NotNull TimeRange timeRange,
-            @NotNull IDeferrableCallback event) {
+    private static void handleTopHelpers(Collection topHelpers,
+            Collection members, TimeRange timeRange, IDeferrableCallback event) {
         Map userIdToMember =
                 members.stream().collect(Collectors.toMap(Member::getIdLong, Function.identity()));
 
@@ -150,7 +151,8 @@ private static void handleTopHelpers(@NotNull Collection topHel
         event.getHook().editOriginal(message).queue();
     }
 
-    private static @NotNull List topHelperToDataRow(@NotNull TopHelperResult topHelper,
+    @Nonnull
+    private static List topHelperToDataRow(TopHelperResult topHelper,
             @Nullable Member member) {
         String id = Long.toString(topHelper.authorId());
         String name = member == null ? "UNKNOWN_USER" : member.getEffectiveName();
@@ -159,8 +161,9 @@ private static void handleTopHelpers(@NotNull Collection topHel
         return List.of(id, name, messageLengths);
     }
 
-    private static @NotNull String dataTableToString(@NotNull Collection> dataTable,
-            @NotNull TimeRange timeRange) {
+    @Nonnull
+    private static String dataTableToString(Collection> dataTable,
+            TimeRange timeRange) {
         return dataTableToAsciiTable(dataTable,
                 List.of(new ColumnSetting("Id", HorizontalAlign.RIGHT),
                         new ColumnSetting("Name", HorizontalAlign.RIGHT),
@@ -169,9 +172,9 @@ private static void handleTopHelpers(@NotNull Collection topHel
                                 HorizontalAlign.RIGHT)));
     }
 
-    private static @NotNull String dataTableToAsciiTable(
-            @NotNull Collection> dataTable,
-            @NotNull List columnSettings) {
+    @Nonnull
+    private static String dataTableToAsciiTable(Collection> dataTable,
+            List columnSettings) {
         IntFunction headerToAlignment = i -> columnSettings.get(i).headerName();
         IntFunction indexToAlignment = i -> columnSettings.get(i).alignment();
 
@@ -186,15 +189,14 @@ private static void handleTopHelpers(@NotNull Collection topHel
         return AsciiTable.getTable(AsciiTable.BASIC_ASCII_NO_DATA_SEPARATORS, dataTable, columns);
     }
 
-    private record TimeRange(@NotNull Instant start, @NotNull Instant end,
-            @NotNull String description) {
+    private record TimeRange(Instant start, Instant end, String description) {
     }
 
 
-    private record TopHelperResult(long authorId, @NotNull BigDecimal messageLengths) {
+    private record TopHelperResult(long authorId, BigDecimal messageLengths) {
     }
 
 
-    private record ColumnSetting(@NotNull String headerName, @NotNull HorizontalAlign alignment) {
+    private record ColumnSetting(String headerName, HorizontalAlign alignment) {
     }
 }
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersMessageListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersMessageListener.java
index 5d43a1d68e..a363c61898 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersMessageListener.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersMessageListener.java
@@ -3,7 +3,6 @@
 import net.dv8tion.jda.api.entities.ChannelType;
 import net.dv8tion.jda.api.entities.ThreadChannel;
 import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
-import org.jetbrains.annotations.NotNull;
 import org.togetherjava.tjbot.commands.MessageReceiverAdapter;
 import org.togetherjava.tjbot.config.Config;
 import org.togetherjava.tjbot.db.Database;
@@ -29,7 +28,7 @@ public final class TopHelpersMessageListener extends MessageReceiverAdapter {
      * @param database to store message meta-data in
      * @param config the config to use for this
      */
-    public TopHelpersMessageListener(@NotNull Database database, @NotNull Config config) {
+    public TopHelpersMessageListener(Database database, Config config) {
         super(Pattern.compile(".*"));
 
         this.database = database;
@@ -41,7 +40,7 @@ public TopHelpersMessageListener(@NotNull Database database, @NotNull Config con
     }
 
     @Override
-    public void onMessageReceived(@NotNull MessageReceivedEvent event) {
+    public void onMessageReceived(MessageReceivedEvent event) {
         if (event.getAuthor().isBot() || event.isWebhookMessage()) {
             return;
         }
@@ -53,7 +52,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) {
         addMessageRecord(event);
     }
 
-    private boolean isHelpThread(@NotNull MessageReceivedEvent event) {
+    private boolean isHelpThread(MessageReceivedEvent event) {
         if (event.getChannelType() != ChannelType.GUILD_PUBLIC_THREAD) {
             return false;
         }
@@ -64,7 +63,7 @@ private boolean isHelpThread(@NotNull MessageReceivedEvent event) {
                 || isOverviewChannelName.test(rootChannelName);
     }
 
-    private void addMessageRecord(@NotNull MessageReceivedEvent event) {
+    private void addMessageRecord(MessageReceivedEvent event) {
         database.write(context -> context.newRecord(HELP_CHANNEL_MESSAGES)
             .setMessageId(event.getMessage().getIdLong())
             .setGuildId(event.getGuild().getIdLong())
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersPurgeMessagesRoutine.java b/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersPurgeMessagesRoutine.java
index 527c908f1d..a685f1af18 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersPurgeMessagesRoutine.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/TopHelpersPurgeMessagesRoutine.java
@@ -1,12 +1,12 @@
 package org.togetherjava.tjbot.commands.tophelper;
 
 import net.dv8tion.jda.api.JDA;
-import org.jetbrains.annotations.NotNull;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.togetherjava.tjbot.commands.Routine;
 import org.togetherjava.tjbot.db.Database;
 
+import javax.annotation.Nonnull;
 import java.time.Instant;
 import java.time.Period;
 import java.util.concurrent.TimeUnit;
@@ -28,17 +28,18 @@ public final class TopHelpersPurgeMessagesRoutine implements Routine {
      *
      * @param database the database that contains the messages to purge
      */
-    public TopHelpersPurgeMessagesRoutine(@NotNull Database database) {
+    public TopHelpersPurgeMessagesRoutine(Database database) {
         this.database = database;
     }
 
     @Override
-    public @NotNull Schedule createSchedule() {
+    @Nonnull
+    public Schedule createSchedule() {
         return new Schedule(ScheduleMode.FIXED_RATE, 0, 4, TimeUnit.HOURS);
     }
 
     @Override
-    public void runRoutine(@NotNull JDA jda) {
+    public void runRoutine(JDA jda) {
         int recordsDeleted =
                 database.writeAndProvide(context -> context.deleteFrom(HELP_CHANNEL_MESSAGES)
                     .where(HELP_CHANNEL_MESSAGES.SENT_AT
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/package-info.java
index 61969abb57..224148b934 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/package-info.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/tophelper/package-info.java
@@ -2,4 +2,7 @@
  * This packages offers all the functionality for the top-helpers command system. The core class is
  * {@link org.togetherjava.tjbot.commands.tophelper.TopHelpersCommand}.
  */
+@ParametersAreNonnullByDefault
 package org.togetherjava.tjbot.commands.tophelper;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/utils/DiscordClientAction.java b/application/src/main/java/org/togetherjava/tjbot/commands/utils/DiscordClientAction.java
index bf3b947e44..0f98a3da4a 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/utils/DiscordClientAction.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/utils/DiscordClientAction.java
@@ -3,8 +3,8 @@
 import net.dv8tion.jda.api.interactions.components.buttons.Button;
 import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
 import org.jetbrains.annotations.Contract;
-import org.jetbrains.annotations.NotNull;
 
+import javax.annotation.Nonnull;
 import java.util.regex.Pattern;
 
 /**
@@ -261,7 +261,8 @@ public String getRawUrl() {
      * @return The formatted URL as an {@link String}
      * @throws IllegalArgumentException When missing arguments
      */
-    public String formatUrl(final String @NotNull... arguments) {
+    @Nonnull
+    public String formatUrl(final String... arguments) {
         String localUrl = url;
 
         for (final String argument : arguments) {
@@ -284,11 +285,13 @@ public String formatUrl(final String @NotNull... arguments) {
      * @return A {@link Button} of {@link ButtonStyle#LINK} with the given label
      * @throws IllegalArgumentException When missing arguments
      */
-    public Button asLinkButton(@NotNull final String label, final String... arguments) {
+    @Nonnull
+    public Button asLinkButton(final String label, final String... arguments) {
         return Button.link(formatUrl(arguments), label);
     }
 
     @Override
+    @Nonnull
     public String toString() {
         return "DiscordClientAction{" + "url='" + url + '\'' + '}';
     }
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/utils/Hashing.java b/application/src/main/java/org/togetherjava/tjbot/commands/utils/Hashing.java
index b019c13864..6b63de1120 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/utils/Hashing.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/utils/Hashing.java
@@ -1,7 +1,6 @@
 package org.togetherjava.tjbot.commands.utils;
 
-import org.jetbrains.annotations.NotNull;
-
+import javax.annotation.Nonnull;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -26,9 +25,8 @@ private Hashing() {
      * @param bytes the binary data to convert
      * @return a hexadecimal representation
      */
-    @SuppressWarnings("MagicNumber")
-    @NotNull
-    public static String bytesToHex(byte @NotNull [] bytes) {
+    @Nonnull
+    public static String bytesToHex(byte[] bytes) {
         Objects.requireNonNull(bytes);
         // See https://stackoverflow.com/a/9855338/2411243
         // noinspection MultiplyOrDivideByPowerOfTwo
@@ -52,7 +50,8 @@ public static String bytesToHex(byte @NotNull [] bytes) {
      * @param data the data to hash
      * @return the computed hash
      */
-    public static byte @NotNull [] hash(@NotNull String method, byte @NotNull [] data) {
+    @Nonnull
+    public static byte[] hash(String method, byte[] data) {
         Objects.requireNonNull(method);
         Objects.requireNonNull(data);
         try {
diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/utils/MessageUtils.java b/application/src/main/java/org/togetherjava/tjbot/commands/utils/MessageUtils.java
index 380b2a50b6..c14a667fe0 100644
--- a/application/src/main/java/org/togetherjava/tjbot/commands/utils/MessageUtils.java
+++ b/application/src/main/java/org/togetherjava/tjbot/commands/utils/MessageUtils.java
@@ -4,8 +4,8 @@
 import net.dv8tion.jda.api.interactions.components.ActionRow;
 import net.dv8tion.jda.api.interactions.components.buttons.Button;
 import net.dv8tion.jda.api.utils.MarkdownSanitizer;
-import org.jetbrains.annotations.NotNull;
 
+import javax.annotation.Nonnull;
 import java.util.List;
 
 /**
@@ -28,7 +28,7 @@ private MessageUtils() {
      * @param message the message that contains at least one button
      * @throws IllegalArgumentException when the given message does not contain any button
      */
-    public static void disableButtons(@NotNull Message message) {
+    public static void disableButtons(Message message) {
         List