diff --git a/application/build.gradle b/application/build.gradle index 80b59cb2a8..b004d0fae6 100644 --- a/application/build.gradle +++ b/application/build.gradle @@ -6,7 +6,7 @@ buildscript { plugins { id 'application' - id 'com.google.cloud.tools.jib' version '3.2.1' + id 'com.google.cloud.tools.jib' version '3.3.0' id 'com.github.johnrengelman.shadow' version '7.1.0' id 'database-settings' } @@ -43,6 +43,7 @@ dependencies { implementation 'org.jetbrains:annotations:23.0.0' implementation project(':database') + implementation project(':utils') implementation 'net.dv8tion:JDA:5.0.0-alpha.9' @@ -62,7 +63,7 @@ dependencies { implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.0' implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0' - implementation 'com.github.freva:ascii-table:1.4.0' + implementation 'com.github.freva:ascii-table:1.6.0' implementation 'com.github.ben-manes.caffeine:caffeine:3.1.1' diff --git a/application/config.json.template b/application/config.json.template index 3a34d248fc..51faf35082 100644 --- a/application/config.json.template +++ b/application/config.json.template @@ -45,5 +45,43 @@ ], "categoryRoleSuffix": " - Helper" }, - "mediaOnlyChannelPattern": "memes" + "mediaOnlyChannelPattern": "memes", + "blacklistedFileExtension": [ + "application", + "bat", + "cmd", + "com", + "cpl", + "exe", + "gadget", + "hta", + "inf", + "jse", + "lnk", + "msc", + "msh", + "msh1", + "msh1xml", + "msh2", + "msh2xml", + "mshxml", + "msi", + "msp", + "pif", + "ps1", + "ps1xml", + "ps2", + "ps2xml", + "psc1", + "psc2", + "scf", + "scr", + "vb", + "vbe", + "vbs", + "ws", + "wsc", + "wsf", + "wsh" + ] } diff --git a/application/src/main/java/org/togetherjava/tjbot/BootstrapLauncher.java b/application/src/main/java/org/togetherjava/tjbot/BootstrapLauncher.java index bd264ca51e..7a29f5895f 100644 --- a/application/src/main/java/org/togetherjava/tjbot/BootstrapLauncher.java +++ b/application/src/main/java/org/togetherjava/tjbot/BootstrapLauncher.java @@ -20,7 +20,6 @@ public static void main(String[] args) { Application.main(args); } - /** * Sets any system-properties before anything else is touched. */ 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 0826682c08..7b71f93443 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/Features.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/Features.java @@ -11,6 +11,7 @@ import org.togetherjava.tjbot.commands.mathcommands.wolframalpha.WolframAlphaCommand; import org.togetherjava.tjbot.commands.mediaonly.MediaOnlyChannelListener; import org.togetherjava.tjbot.commands.moderation.*; +import org.togetherjava.tjbot.commands.moderation.attachment.BlacklistedAttachmentListener; import org.togetherjava.tjbot.commands.moderation.scam.ScamBlocker; import org.togetherjava.tjbot.commands.moderation.scam.ScamHistoryPurgeRoutine; import org.togetherjava.tjbot.commands.moderation.scam.ScamHistoryStore; @@ -31,7 +32,6 @@ 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,13 +59,12 @@ private Features() { * @param config the configuration features should use * @return a collection of all features */ - @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); ScamHistoryStore scamHistoryStore = new ScamHistoryStore(database); - HelpSystemHelper helpSystemHelper = new HelpSystemHelper(config, database); + HelpSystemHelper helpSystemHelper = new HelpSystemHelper(jda, config, database); // NOTE The system can add special system relevant commands also by itself, // hence this list may not necessarily represent the full list of all commands actually @@ -92,6 +91,7 @@ public static Collection createFeatures(JDA jda, Database database, Con features.add(new ImplicitAskListener(config, helpSystemHelper)); features.add(new MediaOnlyChannelListener(config)); features.add(new FileSharingMessageListener(config)); + features.add(new BlacklistedAttachmentListener(config, modAuditLogWriter)); // Event receivers features.add(new RejoinModerationRoleListener(actionsStore, 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 c99e08cf98..b0aaf80d59 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiver.java @@ -3,7 +3,6 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; -import javax.annotation.Nonnull; import java.util.regex.Pattern; /** @@ -28,7 +27,6 @@ public interface MessageReceiver extends Feature { * * @return the pattern matching the names of relevant channels */ - @Nonnull Pattern getChannelNamePattern(); /** 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 b2be566758..63a6bf841a 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/MessageReceiverAdapter.java @@ -3,7 +3,6 @@ import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.events.message.MessageUpdateEvent; -import javax.annotation.Nonnull; import java.util.regex.Pattern; /** @@ -29,7 +28,6 @@ protected MessageReceiverAdapter(Pattern channelNamePattern) { } @Override - @Nonnull public final Pattern getChannelNamePattern() { return channelNamePattern; } 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 1d684bf6a7..0b9456aa2b 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/Routine.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/Routine.java @@ -2,7 +2,6 @@ import net.dv8tion.jda.api.JDA; -import javax.annotation.Nonnull; import java.util.concurrent.TimeUnit; /** @@ -24,7 +23,6 @@ public interface Routine extends Feature { * * @return the schedule of this routine */ - @Nonnull Schedule createSchedule(); /** @@ -49,7 +47,6 @@ public interface Routine extends Feature { record Schedule(ScheduleMode mode, long initialDuration, long duration, TimeUnit unit) { } - /** * Whether subsequent executions of a routine are executed at a fixed rate or are delayed. */ 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 551e4474ec..9618c7412f 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommand.java @@ -13,7 +13,6 @@ import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator; import org.togetherjava.tjbot.commands.componentids.Lifespan; -import javax.annotation.Nonnull; import java.util.List; /** @@ -49,7 +48,6 @@ public interface SlashCommand extends UserInteractor { * * @return the description of the command */ - @Nonnull String getDescription(); /** @@ -59,7 +57,6 @@ public interface SlashCommand extends UserInteractor { * * @return the visibility of the command */ - @Nonnull SlashCommandVisibility getVisibility(); /** @@ -77,7 +74,6 @@ public interface SlashCommand extends UserInteractor { * * @return the command data of this command */ - @Nonnull SlashCommandData getData(); /** 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 d0d2ee94c4..cc071fd767 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommandAdapter.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/SlashCommandAdapter.java @@ -15,7 +15,6 @@ 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; @@ -90,25 +89,21 @@ protected SlashCommandAdapter(String name, String description, } @Override - @Nonnull public final String getName() { return name; } @Override - @Nonnull public final String getDescription() { return description; } @Override - @Nonnull public final SlashCommandVisibility getVisibility() { return visibility; } @Override - @Nonnull public final SlashCommandData getData() { return data; } @@ -145,7 +140,6 @@ public void onSelectionMenu(SelectMenuInteractionEvent event, List args) * @return the generated component ID */ @SuppressWarnings("OverloadedVarargsMethod") - @Nonnull protected final String generateComponentId(String... args) { return generateComponentId(Lifespan.REGULAR, args); } @@ -163,7 +157,6 @@ protected final String generateComponentId(String... args) { * @return the generated component ID */ @SuppressWarnings({"OverloadedVarargsMethod", "WeakerAccess"}) - @Nonnull protected final String generateComponentId(Lifespan lifespan, String... args) { return Objects.requireNonNull(componentIdGenerator) .generate(new ComponentId(getName(), Arrays.asList(args)), lifespan); @@ -194,7 +187,6 @@ protected final String generateComponentId(Lifespan lifespan, String... args) { * @return the generated list of options */ @Unmodifiable - @Nonnull protected static List generateMultipleOptions(OptionData optionData, @Range(from = 1, to = 25) int amount) { String baseName = optionData.getName(); @@ -216,7 +208,6 @@ protected static List generateMultipleOptions(OptionData optionData, * @return all options with the given prefix */ @Unmodifiable - @Nonnull protected static List getMultipleOptionsByNamePrefix( CommandInteractionPayload event, String namePrefix) { return event.getOptions() 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 68a916369c..b46cb8069b 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/UserInteractor.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/UserInteractor.java @@ -5,7 +5,6 @@ import net.dv8tion.jda.api.events.interaction.component.SelectMenuInteractionEvent; import org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator; -import javax.annotation.Nonnull; import java.util.List; /** @@ -27,7 +26,6 @@ public interface UserInteractor extends Feature { * * @return the name of the interactor */ - @Nonnull String getName(); /** 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 be5550bdb9..6b0e1376c2 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 @@ -19,13 +19,11 @@ 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; import java.util.stream.Collectors; - /** * Implements the {@code /role-select} command. *

@@ -57,7 +55,6 @@ public final class RoleSelectCommand extends SlashCommandAdapter { private static final int OPTIONAL_ROLES_AMOUNT = 22; - /** * Construct an instance. */ @@ -193,7 +190,6 @@ private void sendRoleSelectionMenu(final CommandInteraction event, event.replyEmbeds(embed).addActionRow(menu.build()).queue(); } - @Nonnull private static SelectOption mapToSelectOption(Role role) { RoleIcon roleIcon = role.getIcon(); @@ -243,7 +239,6 @@ private static void handleRoleSelection(SelectMenuInteractionEvent event, Guild modifyRoles(event, event.getMember(), guild, rolesToAdd, rolesToRemove); } - @Nonnull private static Function> optionToRole(Guild guild) { return option -> { Role role = guild.getRoleById(option.getValue()); @@ -265,7 +260,6 @@ private static void modifyRoles(IReplyCallback event, Member target, Guild guild .queue(); } - @Nonnull private static MessageEmbed createEmbed(String title, CharSequence description) { return new EmbedBuilder().setTitle(title) .setDescription(description) 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 84bd30ece1..f6bc7965b7 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 @@ -12,7 +12,6 @@ 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; @@ -89,7 +88,6 @@ private static void reactWith(String emoteName, String fallbackUnicodeEmote, Gui }); } - @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 6339bac007..33f97035b4 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 @@ -18,7 +18,6 @@ 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; @@ -26,7 +25,6 @@ import java.util.Optional; import java.util.concurrent.TimeUnit; - /** * Implements the {@code vc-activity} command. Creates VC activities. * @@ -125,24 +123,20 @@ public VcActivityCommand() { "Starts a VC activity (you need to be in an voice channel to run this command)", SlashCommandVisibility.GUILD); - SubcommandData applicationSubCommand = new SubcommandData(APPLICATION_SUBCOMMAND, "Choose an application from our list") .addOptions(new OptionData(OptionType.STRING, APPLICATION_OPTION, "the application", true).addChoices(VC_APPLICATIONS)) .addOptions(inviteOptions); - SubcommandData idSubCommand = new SubcommandData("id", "specify the ID for the application manually") .addOption(OptionType.STRING, ID_OPTION, "the ID of the application", true) .addOptions(inviteOptions); - getData().addSubcommands(applicationSubCommand, idSubCommand); } - @Override public void onSlashCommand(SlashCommandInteractionEvent event) { Member member = Objects.requireNonNull(event.getMember(), "member is null"); @@ -191,7 +185,6 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { handleSubcommand(event, voiceChannel, applicationId, maxUses, maxAgeDays, applicationName); } - @Nonnull private static Optional getKeyByValue(Map map, V value) { for (Map.Entry entry : map.entrySet()) { if (value.equals(entry.getKey())) { @@ -206,7 +199,6 @@ private static void handleSubcommand(SlashCommandInteractionEvent event, VoiceChannel voiceChannel, String applicationId, @Nullable Integer maxUses, @Nullable Integer maxAgeDays, String applicationName) { - voiceChannel.createInvite() .setTargetApplication(applicationId) .setMaxUses(maxUses) @@ -217,7 +209,6 @@ private static void handleSubcommand(SlashCommandInteractionEvent event, } - @Nonnull private static ReplyCallbackAction replyInvite(SlashCommandInteractionEvent event, Invite invite, String applicationName) { return event.reply(""" 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 177ae9c4c3..0c110ffc26 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,7 +2,10 @@ * This package offers some basic commands that act as example for how to use the command system of * the application. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.basic; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; 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 91cd7a3228..dd8035e8d0 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 @@ -7,8 +7,6 @@ import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import org.togetherjava.tjbot.commands.SlashCommand; -import javax.annotation.Nonnull; - /** * Provides component ID generation. *

@@ -37,6 +35,5 @@ public interface ComponentIdGenerator { * @throws InvalidComponentIdFormatException if the given component ID was in an unexpected * format and could not be serialized */ - @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 6d5071c787..4e17409c6e 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 @@ -6,7 +6,6 @@ import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; -import javax.annotation.Nonnull; import java.util.Optional; /** @@ -38,6 +37,5 @@ public interface ComponentIdParser { * @throws InvalidComponentIdFormatException if the component ID associated to the given UUID * was in an unexpected format and could not be deserialized */ - @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 882505d8ba..cbbf106f50 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 @@ -13,7 +13,6 @@ 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; @@ -155,7 +154,6 @@ public void addComponentIdRemovedListener(Consumer listener) { * format and could not be serialized */ @SuppressWarnings("WeakerAccess") - @Nonnull public Optional get(UUID uuid) { synchronized (storeLock) { // Get it from the cache or, if not found, the database @@ -217,7 +215,6 @@ public void putOrThrow(UUID uuid, ComponentId componentId, Lifespan lifespan) { } } - @Nonnull private Optional getFromDatabase(UUID uuid) { return database.read(context -> Optional .ofNullable(context.selectFrom(ComponentIds.COMPONENT_IDS) @@ -294,7 +291,6 @@ private void evictDatabase() { } } - @Nonnull private static String serializeComponentId(ComponentId componentId) { try { return CSV.writerFor(ComponentId.class) @@ -305,7 +301,6 @@ private static String serializeComponentId(ComponentId componentId) { } } - @Nonnull private static ComponentId deserializeComponentId(String componentId) { try { return CSV.readerFor(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 e52a9953c4..f982878027 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 @@ -10,7 +10,10 @@ * {@link org.togetherjava.tjbot.commands.componentids.ComponentIdGenerator} and * {@link org.togetherjava.tjbot.commands.componentids.ComponentIdParser}. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.componentids; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 2267fe851d..c36b37730d 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 @@ -13,7 +13,6 @@ 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; @@ -79,7 +78,6 @@ public void onMessageReceived(MessageReceivedEvent event) { return; } - List attachments = event.getMessage() .getAttachments() .stream() @@ -109,7 +107,6 @@ private boolean isAttachmentRelevant(Message.Attachment attachment) { return extensionFilter.contains(extension); } - private void processAttachments(MessageReceivedEvent event, List attachments) { @@ -133,7 +130,6 @@ private void processAttachments(MessageReceivedEvent event, sendResponse(event, url); } - @Nonnull private String readAttachment(InputStream stream) { try (stream) { return new String(stream.readAllBytes(), StandardCharsets.UTF_8); @@ -142,7 +138,6 @@ private String readAttachment(InputStream stream) { } } - @Nonnull private String getNameOf(Message.Attachment attachment) { String fileName = attachment.getFileName(); String fileExtension = attachment.getFileExtension(); @@ -163,7 +158,6 @@ private String getNameOf(Message.Attachment attachment) { return fileName; } - @Nonnull private String uploadToGist(GistRequest jsonRequest) { String body; try { 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 1d35277fcb..7359bf5006 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 @@ -3,8 +3,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import javax.annotation.Nonnull; - /** * @see Create a Gist via * API @@ -14,7 +12,6 @@ final class GistResponse { @JsonProperty("html_url") private String htmlUrl; - @Nonnull public String getHtmlUrl() { return 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 8f5f6befeb..f1ef60813e 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,7 +2,10 @@ * This package offers all the functionality for automatically uploading files to sharing services. * The core class is {@link org.togetherjava.tjbot.commands.filesharing.FileSharingMessageListener}. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.filesharing; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 16968d2d9b..451ba9d4bf 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 @@ -15,7 +15,6 @@ 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; @@ -119,7 +118,6 @@ private boolean handleIsValidTitle(CharSequence title, IReplyCallback event) { return false; } - @Nonnull private RestAction handleEvent(InteractionHook eventHook, ThreadChannel threadChannel, Member author, String title, String category, Guild guild) { helper.writeHelpThreadToDatabase(author, threadChannel); @@ -128,7 +126,6 @@ private RestAction handleEvent(InteractionHook eventHook, ThreadChannel .flatMap(any -> helper.sendExplanationMessage(threadChannel)); } - @Nonnull private RestAction sendInitialMessage(Guild guild, ThreadChannel threadChannel, Member author, String title, String category) { String roleMentionDescription = helper.handleFindRoleForCategory(category, guild) @@ -148,7 +145,6 @@ private RestAction sendInitialMessage(Guild guild, ThreadChannel thread .flatMap(message -> message.editMessage(contentWithRole)); } - @Nonnull private static RestAction notifyUser(InteractionHook eventHook, IMentionable threadChannel) { return eventHook.editOriginal(""" 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 bef93f9889..2623c1b13f 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 @@ -12,7 +12,6 @@ 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; @@ -59,7 +58,6 @@ public AutoPruneHelperRoutine(Config config, HelpSystemHelper helper, } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, 1, TimeUnit.HOURS); } 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 f066380f27..0ebe47f21e 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 @@ -13,7 +13,6 @@ 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; @@ -54,7 +53,6 @@ public BotMessageCleanup(Config config) { } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 1, 1, TimeUnit.MINUTES); } @@ -79,7 +77,6 @@ private void cleanupBotMessagesForGuild(Guild guild) { .queue(); } - @Nonnull private Optional handleRequireStagingChannel(Guild guild) { Optional maybeChannel = guild.getTextChannelCache() .stream() @@ -108,7 +105,6 @@ private static boolean shouldMessageBeCleanedUp(Message message) { return deleteWhen.isBefore(Instant.now()); } - @Nonnull private static RestAction cleanupBotMessages(GuildMessageChannel channel, Collection messages) { logger.debug("Cleaning up old bot messages in the staging channel"); 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 1f84add910..fd884591f8 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 @@ -15,7 +15,6 @@ 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; @@ -96,7 +95,6 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { .queue(); } - @Nonnull private RestAction sendCategoryChangedMessage(Guild guild, InteractionHook hook, ThreadChannel helpThread, String category) { String changedContent = "Changed the category to **%s**.".formatted(category); 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 e8500af163..23bf93705f 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 @@ -1,6 +1,8 @@ package org.togetherjava.tjbot.commands.help; import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.*; import net.dv8tion.jda.api.requests.RestAction; import net.dv8tion.jda.api.requests.restaction.MessageAction; @@ -13,13 +15,15 @@ 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; import java.util.Locale; import java.util.Optional; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.regex.Matcher; @@ -47,20 +51,26 @@ public final class HelpSystemHelper { static final int TITLE_COMPACT_LENGTH_MIN = 2; static final int TITLE_COMPACT_LENGTH_MAX = 70; + private static final ScheduledExecutorService SERVICE = Executors.newScheduledThreadPool(3); + private static final int SEND_UNCATEGORIZED_ADVICE_AFTER_MINUTES = 5; + private final Predicate isOverviewChannelName; private final String overviewChannelPattern; private final Predicate isStagingChannelName; private final String stagingChannelPattern; private final String categoryRoleSuffix; private final Database database; + private final JDA jda; /** * Creates a new instance. * + * @param jda the JDA instance to use * @param config the config to use * @param database the database to store help thread metadata in */ - public HelpSystemHelper(Config config, Database database) { + public HelpSystemHelper(JDA jda, Config config, Database database) { + this.jda = jda; HelpSystemConfig helpConfig = config.getHelpSystem(); this.database = database; @@ -73,7 +83,6 @@ public HelpSystemHelper(Config config, Database database) { categoryRoleSuffix = helpConfig.getCategoryRoleSuffix(); } - @Nonnull RestAction sendExplanationMessage(MessageChannel threadChannel) { boolean useCodeSyntaxExampleImage = true; InputStream codeSyntaxExampleData = @@ -120,12 +129,10 @@ void writeHelpThreadToDatabase(Member author, ThreadChannel threadChannel) { }); } - @Nonnull private static MessageEmbed embedWith(CharSequence message) { return embedWith(message, null); } - @Nonnull private static MessageEmbed embedWith(CharSequence message, @Nullable String imageUrl) { return new EmbedBuilder().setColor(AMBIENT_COLOR) .setDescription(message) @@ -133,7 +140,6 @@ private static MessageEmbed embedWith(CharSequence message, @Nullable String ima .build(); } - @Nonnull Optional handleFindRoleForCategory(String category, Guild guild) { String roleName = category + categoryRoleSuffix; Optional maybeHelperRole = guild.getRolesByName(roleName, true).stream().findAny(); @@ -145,12 +151,10 @@ Optional handleFindRoleForCategory(String category, Guild guild) { return maybeHelperRole; } - @Nonnull Optional getCategoryOfChannel(Channel channel) { return Optional.ofNullable(HelpThreadName.ofChannelName(channel.getName()).category); } - @Nonnull RestAction renameChannelToCategory(GuildChannel channel, String category) { HelpThreadName currentName = HelpThreadName.ofChannelName(channel.getName()); HelpThreadName nextName = @@ -159,7 +163,6 @@ RestAction renameChannelToCategory(GuildChannel channel, String category) return renameChannel(channel, currentName, nextName); } - @Nonnull RestAction renameChannelToTitle(GuildChannel channel, String title) { HelpThreadName currentName = HelpThreadName.ofChannelName(channel.getName()); HelpThreadName nextName = @@ -168,7 +171,6 @@ RestAction renameChannelToTitle(GuildChannel channel, String title) { return renameChannel(channel, currentName, nextName); } - @Nonnull RestAction renameChannelToActivity(GuildChannel channel, ThreadActivity activity) { HelpThreadName currentName = HelpThreadName.ofChannelName(channel.getName()); HelpThreadName nextName = @@ -177,7 +179,6 @@ RestAction renameChannelToActivity(GuildChannel channel, ThreadActivity ac return renameChannel(channel, currentName, nextName); } - @Nonnull private RestAction renameChannel(GuildChannel channel, HelpThreadName currentName, HelpThreadName nextName) { if (currentName.equals(nextName)) { @@ -192,7 +193,6 @@ boolean isOverviewChannelName(String channelName) { return isOverviewChannelName.test(channelName); } - @Nonnull String getOverviewChannelPattern() { return overviewChannelPattern; } @@ -201,7 +201,6 @@ boolean isStagingChannelName(String channelName) { return isStagingChannelName.test(channelName); } - @Nonnull String getStagingChannelPattern() { return stagingChannelPattern; } @@ -214,7 +213,6 @@ static boolean isTitleValid(CharSequence title) { && !titleCompact.toLowerCase(Locale.US).contains("help"); } - @Nonnull Optional handleRequireOverviewChannel(Guild guild, Consumer consumeChannelPatternIfNotFound) { Predicate isChannelName = this::isOverviewChannelName; @@ -232,7 +230,6 @@ Optional handleRequireOverviewChannel(Guild guild, return maybeChannel; } - @Nonnull Optional handleRequireOverviewChannelForAsk(Guild guild, MessageChannel respondTo) { return handleRequireOverviewChannel(guild, channelPattern -> { @@ -246,7 +243,6 @@ Optional handleRequireOverviewChannelForAsk(Guild guild, }); } - @Nonnull List getActiveThreadsIn(TextChannel channel) { return channel.getThreadChannels() .stream() @@ -254,9 +250,52 @@ List getActiveThreadsIn(TextChannel channel) { .toList(); } + void scheduleUncategorizedAdviceCheck(long threadChannelId, long authorId) { + SERVICE.schedule(() -> { + try { + executeUncategorizedAdviceCheck(threadChannelId, authorId); + } catch (Exception e) { + logger.warn( + "Unknown error during an uncategorized advice check on thread {} by author {}.", + threadChannelId, authorId, e); + } + }, SEND_UNCATEGORIZED_ADVICE_AFTER_MINUTES, TimeUnit.MINUTES); + } + + private void executeUncategorizedAdviceCheck(long threadChannelId, long authorId) { + logger.debug("Executing uncategorized advice check for thread {} by author {}.", + threadChannelId, authorId); + jda.retrieveUserById(authorId).flatMap(author -> { + ThreadChannel threadChannel = jda.getThreadChannelById(threadChannelId); + if (threadChannel == null) { + logger.debug( + "Channel for uncategorized advice check seems to be deleted (thread {} by author {}).", + threadChannelId, authorId); + return new CompletedRestAction<>(jda, null); + } + + Optional category = getCategoryOfChannel(threadChannel); + if (category.isPresent()) { + logger.debug( + "Channel for uncategorized advice check seems to have a category now (thread {} by author {}).", + threadChannelId, authorId); + return new CompletedRestAction<>(jda, null); + } + + // Still no category, send advice + MessageEmbed embed = HelpSystemHelper.embedWith( + """ + Hey there πŸ‘‹ You have to select a category for your help thread, otherwise nobody can see your question. + Please use the `/change-help-category` slash-command and pick what fits best, thanks πŸ™‚ + """); + Message message = new MessageBuilder(author.getAsMention()).setEmbeds(embed).build(); + + return threadChannel.sendMessage(message); + }).queue(); + } + record HelpThreadName(@Nullable ThreadActivity activity, @Nullable String category, String title) { - @Nonnull static HelpThreadName ofChannelName(CharSequence channelName) { Matcher matcher = EXTRACT_HELP_NAME_PATTERN.matcher(channelName); @@ -274,7 +313,6 @@ static HelpThreadName ofChannelName(CharSequence channelName) { return new HelpThreadName(activity, category, title); } - @Nonnull String toChannelName() { String activityText = activity == null ? "" : activity.getSymbol() + " "; String categoryText = category == null ? "" : "[%s] ".formatted(category); @@ -294,12 +332,10 @@ enum ThreadActivity { this.symbol = symbol; } - @Nonnull public String getSymbol() { return symbol; } - @Nonnull static ThreadActivity ofSymbol(String symbol) { return Stream.of(values()) .filter(activity -> activity.getSymbol().equals(symbol)) 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 9cf9a42c30..79553fcdee 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 @@ -7,7 +7,6 @@ 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; @@ -38,7 +37,6 @@ public HelpThreadActivityUpdater(HelpSystemHelper helper) { } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 1, SCHEDULE_MINUTES, TimeUnit.MINUTES); } @@ -74,7 +72,6 @@ private void updateActivityForThread(ThreadChannel threadChannel) { .queue(); } - @Nonnull private static RestAction determineActivity( MessageChannel channel) { return channel.getHistory().retrievePast(ACTIVITY_DETERMINE_MESSAGE_LIMIT).map(messages -> { 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 b8f3689666..7185bf20a4 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 @@ -8,7 +8,6 @@ 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; @@ -36,7 +35,6 @@ public HelpThreadAutoArchiver(HelpSystemHelper helper) { } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, SCHEDULE_MINUTES, TimeUnit.MINUTES); } @@ -67,7 +65,6 @@ private void autoArchiveForGuild(Guild guild) { .forEach(activeThread -> autoArchiveForThread(activeThread, archiveAfterMoment)); } - @Nonnull private Instant computeArchiveAfterMoment() { return Instant.now().minus(ARCHIVE_AFTER_INACTIVITY_OF); } 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 4393b837be..929b5c5b6d 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 @@ -7,7 +7,6 @@ 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; @@ -30,7 +29,6 @@ public HelpThreadMetadataPurger(Database database) { } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, 4, TimeUnit.HOURS); } 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 0905c4991b..eb32a0e5ac 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 @@ -12,7 +12,6 @@ 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; @@ -59,7 +58,6 @@ public HelpThreadOverviewUpdater(Config config, HelpSystemHelper helper) { } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 1, 1, TimeUnit.MINUTES); } @@ -124,7 +122,6 @@ private void updateOverview(TextChannel overviewChannel) { .queue(); } - @Nonnull private String createDescription(Collection activeThreads) { if (activeThreads.isEmpty()) { return "Currently none."; @@ -150,7 +147,6 @@ private String createDescription(Collection activeThreads) { .collect(Collectors.joining("\n\n")); } - @Nonnull private static RestAction> getStatusMessage(MessageChannel channel) { return channel.getHistory() .retrievePast(1) @@ -168,7 +164,6 @@ private static boolean isStatusMessage(Message message) { return content.startsWith(STATUS_TITLE); } - @Nonnull private RestAction sendUpdatedOverview(@Nullable Message statusMessage, Message updatedStatusMessage, MessageChannel overviewChannel) { logger.debug("Sending the updated question overview"); @@ -203,7 +198,6 @@ String toDiscordString() { return "**%s**:%n%s".formatted(category, threadListText); } - @Nonnull static CategoryWithThreads ofEntry( Map.Entry> categoryAndThreads) { return new CategoryWithThreads(categoryAndThreads.getKey(), 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 3a9c37452d..46086246cb 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 @@ -15,7 +15,6 @@ 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; @@ -125,7 +124,6 @@ private boolean handleIsNotOnCooldown(Message message) { return false; } - @Nonnull private Optional getLastHelpThreadIfOnCooldown(long userId) { return Optional.ofNullable(userIdToLastHelpThread.getIfPresent(userId)) .filter(lastHelpThread -> { @@ -137,7 +135,6 @@ private Optional getLastHelpThreadIfOnCooldown(long userId) { }); } - @Nonnull private static String createTitle(String message) { String titleCandidate; if (message.length() < TITLE_MAX_LENGTH) { @@ -156,7 +153,6 @@ private static String createTitle(String message) { return HelpSystemHelper.isTitleValid(titleCandidate) ? titleCandidate : "Untitled"; } - @Nonnull private RestAction handleEvent(ThreadChannel threadChannel, Message message, String title) { Member author = message.getMember(); helper.writeHelpThreadToDatabase(author, threadChannel); @@ -166,16 +162,14 @@ private RestAction handleEvent(ThreadChannel threadChannel, Message message, return sendInitialMessage(threadChannel, message, title) .flatMap(any -> notifyUser(threadChannel, message)) .flatMap(any -> message.delete()) - .flatMap(any -> helper.sendExplanationMessage(threadChannel)); - } - - @Nonnull - private static RestAction inviteUsersToThread(ThreadChannel threadChannel, - Member author) { - return threadChannel.addThreadMember(author); + .flatMap(any -> helper.sendExplanationMessage(threadChannel)) + .map(any -> { + helper.scheduleUncategorizedAdviceCheck(threadChannel.getIdLong(), + author.getIdLong()); + return null; + }); } - @Nonnull private static MessageAction sendInitialMessage(ThreadChannel threadChannel, Message originalMessage, String title) { String content = originalMessage.getContentRaw(); @@ -194,11 +188,9 @@ private static MessageAction sendInitialMessage(ThreadChannel threadChannel, Please use `/change-help-category` to greatly increase the visibility of the question.""" .formatted(author, title)).setEmbeds(embed).build(); - return threadChannel.sendMessage(threadMessage); } - @Nonnull private static MessageAction notifyUser(IMentionable threadChannel, Message message) { return message.getChannel() .sendMessage( 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 351316091a..c957b34899 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,7 +2,10 @@ * 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}. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.help; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 2b52137b76..c81e1f7be6 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 @@ -14,7 +14,6 @@ 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; @@ -97,7 +96,6 @@ public void onSlashCommand(final SlashCommandInteractionEvent event) { } } - @Nonnull private Image renderImage(TeXFormula formula) { Image image = formula.createBufferedImage(TeXConstants.STYLE_DISPLAY, DEFAULT_IMAGE_SIZE, FOREGROUND_COLOR, BACKGROUND_COLOR); @@ -117,7 +115,6 @@ private void sendImage(IDeferrableCallback event, String userID, Image image) .queue(); } - @Nonnull private ByteArrayOutputStream getRenderedTextImageStream(Image image) throws IOException { BufferedImage renderedTextImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_4BYTE_ABGR); @@ -137,7 +134,6 @@ private ByteArrayOutputStream getRenderedTextImageStream(Image image) throws IOE * @param latex the latex to convert * @return the converted latex */ - @Nonnull private String convertInlineLatexToFull(String latex) { if (isInvalidInlineFormat(latex)) { throw new ParseException(INVALID_INLINE_FORMAT_ERROR_MESSAGE); 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 753e2ddc70..2d53992e68 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 @@ -9,7 +9,6 @@ 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; @@ -73,7 +72,6 @@ final class WolframAlphaHandler { * @param apiResponse response of the Wolfram Alpha API query * @return user-friendly message for display, as list of embeds */ - @Nonnull HandlerResponse handleApiResponse(HttpResponse apiResponse) { // Check status code int statusCode = apiResponse.statusCode(); @@ -111,7 +109,6 @@ HandlerResponse handleApiResponse(HttpResponse apiResponse) { return handleSuccessfulResponse(queryResult); } - @Nonnull private HandlerResponse handleMisunderstoodQuery(QueryResult result) { StringJoiner output = new StringJoiner("\n"); output.add("Sorry, I did not understand your query."); @@ -152,7 +149,6 @@ private HandlerResponse handleMisunderstoodQuery(QueryResult result) { return responseOf(output.toString()); } - @Nonnull private static String createBulletPointList(Collection elements, Function elementToText) { return elements.stream() @@ -161,7 +157,6 @@ private static String createBulletPointList(Collection elements .collect(Collectors.joining("\n")); } - @Nonnull private HandlerResponse handleSuccessfulResponse(QueryResult queryResult) { StringJoiner messages = new StringJoiner("\n\n"); messages.add("Click the link to see full results."); @@ -201,7 +196,6 @@ private HandlerResponse handleSuccessfulResponse(QueryResult queryResult) { return responseOf(messages.toString(), tilesToDisplay); } - @Nonnull private HandlerResponse responseOf(CharSequence text) { MessageEmbed embed = new EmbedBuilder().setTitle(buildTitle(), userApiQuery) .setDescription(text) @@ -211,7 +205,6 @@ private HandlerResponse responseOf(CharSequence text) { return new HandlerResponse(List.of(embed), List.of()); } - @Nonnull private HandlerResponse responseOf(CharSequence text, Collection tiles) { List embeds = new ArrayList<>(); @@ -237,7 +230,6 @@ private HandlerResponse responseOf(CharSequence text, return new HandlerResponse(embeds, attachments); } - @Nonnull private String buildTitle() { return query + " - " + SERVICE_NAME; } @@ -245,7 +237,6 @@ private String buildTitle() { record HandlerResponse(List embeds, List attachments) { } - record Attachment(String name, byte[] data) { @Override public boolean equals(Object 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 3adbbf9ed7..b1287e2b2d 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 @@ -3,7 +3,6 @@ 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 +38,6 @@ private WolframAlphaImages() { throw new UnsupportedOperationException("Utility class, construction not supported"); } - @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; @@ -56,7 +54,6 @@ static BufferedImage renderTitle(String title) { return image; } - @Nonnull static BufferedImage renderSubPod(SubPod subPod) { WolframAlphaImage sourceImage = subPod.getImage(); @@ -77,12 +74,10 @@ static BufferedImage renderSubPod(SubPod subPod) { return destinationImage; } - @Nonnull static BufferedImage renderFooter() { return new BufferedImage(1, IMAGE_MARGIN_PX, BufferedImage.TYPE_4BYTE_ABGR); } - @Nonnull static List combineImagesIntoTiles(Collection images, int maxTileHeight) { if (images.isEmpty()) { @@ -124,7 +119,6 @@ private static boolean wouldTileBeTooLargeIfAddingImage(int tileHeight, int heig return tileHeight != 0 && tileHeight + heightOfImageToAdd > maxTileHeight; } - @Nonnull private static BufferedImage combineImages(Collection images, int widthPx) { if (images.isEmpty()) { @@ -151,7 +145,6 @@ private static BufferedImage combineImages(Collection i return destinationImage; } - @Nonnull static byte[] imageToBytes(RenderedImage img) { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { ImageIO.write(img, IMAGE_FORMAT, outputStream); diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/DidYouMeans.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/DidYouMeans.java index 2d5e88e7ab..ff5eb47017 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/DidYouMeans.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/DidYouMeans.java @@ -52,6 +52,4 @@ public void setDidYouMeanTips(List didYouMeanTips) { this.didYouMeanTips = new ArrayList<>(didYouMeanTips); } - - } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/Error.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/Error.java index cc9d6b0136..fa8bcfa3db 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/Error.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/Error.java @@ -32,5 +32,4 @@ public void setMessage(String message) { this.message = message; } - } diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/LanguageMessage.java b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/LanguageMessage.java index 5b43c51416..c352af94c8 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/LanguageMessage.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mathcommands/wolframalpha/api/LanguageMessage.java @@ -43,5 +43,4 @@ public void setOther(String other) { this.other = other; } - } 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 eb5e9633c4..39db8406b2 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,7 +3,10 @@ * WolframAlpha * API. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.mathcommands.wolframalpha.api; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 eb9db3d28a..ec0a220c02 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,7 +2,10 @@ * This packages offers all the functionality for the wolfram-alpha command. Sending queries to * their official API, rendering results and displaying them. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.mathcommands.wolframalpha; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/mediaonly/MediaOnlyChannelListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/mediaonly/MediaOnlyChannelListener.java index b67b6031cf..b2bce6613f 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/mediaonly/MediaOnlyChannelListener.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/mediaonly/MediaOnlyChannelListener.java @@ -4,13 +4,12 @@ import net.dv8tion.jda.api.MessageBuilder; import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.entities.MessageType; import net.dv8tion.jda.api.events.message.MessageReceivedEvent; import net.dv8tion.jda.api.requests.RestAction; -import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import org.togetherjava.tjbot.commands.MessageReceiverAdapter; import org.togetherjava.tjbot.config.Config; -import javax.annotation.Nonnull; import java.awt.Color; import java.util.regex.Pattern; @@ -32,37 +31,29 @@ public MediaOnlyChannelListener(Config config) { super(Pattern.compile(config.getMediaOnlyChannelPattern())); } - @Override public void onMessageReceived(MessageReceivedEvent event) { if (event.getAuthor().isBot() || event.isWebhookMessage()) { return; } - if (messageHasNoMediaAttached(event)) { - deleteMessage(event).flatMap(any -> dmUser(event)).queue(); + Message message = event.getMessage(); + if (message.getType() == MessageType.THREAD_CREATED) { + return; + } + + if (messageHasNoMediaAttached(message)) { + message.delete().flatMap(any -> dmUser(message)).queue(); } } - private static boolean messageHasNoMediaAttached(MessageReceivedEvent event) { - Message message = event.getMessage(); + private boolean messageHasNoMediaAttached(Message message) { return message.getAttachments().isEmpty() && message.getEmbeds().isEmpty() && !message.getContentRaw().contains("http"); } - @Nonnull - private AuditableRestAction deleteMessage(MessageReceivedEvent event) { - return event.getMessage().delete(); - } - - @Nonnull - private RestAction dmUser(MessageReceivedEvent event) { - return dmUser(event.getMessage()); - } - - @Nonnull - private RestAction dmUser(Message originalMessage) { - String originalMessageContent = originalMessage.getContentRaw(); + private RestAction dmUser(Message message) { + String originalMessageContent = message.getContentRaw(); MessageEmbed originalMessageEmbed = new EmbedBuilder().setDescription(originalMessageContent) .setColor(Color.ORANGE) @@ -73,7 +64,7 @@ private RestAction dmUser(Message originalMessage) { .setEmbeds(originalMessageEmbed) .build(); - return originalMessage.getAuthor() + return message.getAuthor() .openPrivateChannel() .flatMap(channel -> channel.sendMessage(dmMessage)); } 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 f7ca36833a..cf4c1075ba 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 @@ -2,7 +2,6 @@ import org.togetherjava.tjbot.db.generated.tables.records.ModerationActionsRecord; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.time.Instant; @@ -29,7 +28,6 @@ public record ActionRecord(int caseId, Instant issuedAt, long guildId, long auth * @param action the action to convert * @return the corresponding action record */ - @Nonnull static ActionRecord of(ModerationActionsRecord action) { return new ActionRecord(action.getCaseId(), action.getIssuedAt(), action.getGuildId(), action.getAuthorId(), action.getTargetId(), 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 c59884b593..983ff7aa24 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 @@ -17,7 +17,6 @@ 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; @@ -87,7 +86,6 @@ private boolean handleChecks(Member bot, Member author, @Nullable Member target, * can contain {@link AuditCommand#MAX_PAGE_LENGTH} actions, {@code -1} encodes the last * page */ - @Nonnull private RestAction auditUser(long guildId, long targetId, long callerId, int pageNumber, JDA jda) { List actions = actionsStore.getActionsByTargetAscending(guildId, targetId); @@ -109,7 +107,6 @@ private RestAction auditUser(long guildId, long targetId, long callerId guildId, targetId, callerId)); } - @Nonnull private List> groupActionsByPages(List actions) { List> groupedActions = new ArrayList<>(); for (int i = 0; i < actions.size(); i++) { @@ -127,7 +124,6 @@ private static int clamp(int minInclusive, int value, int maxInclusive) { return Math.min(Math.max(minInclusive, value), maxInclusive); } - @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()) @@ -135,7 +131,6 @@ private static EmbedBuilder createSummaryEmbed(User user, Collection actions) { int actionAmount = actions.size(); @@ -161,7 +156,6 @@ private static String createSummaryMessageDescription(Collection a return shortSummary + "\n" + typeCountSummary; } - @Nonnull private RestAction attachEmbedFields(EmbedBuilder auditEmbed, List> groupedActions, int pageNumber, int totalPages, JDA jda) { @@ -181,7 +175,6 @@ private RestAction attachEmbedFields(EmbedBuilder auditEmbed, }); } - @Nonnull private static RestAction actionToField(ActionRecord action, JDA jda) { return jda.retrieveUserById(action.authorId()) .map(author -> author == null ? "(unknown user)" : author.getAsTag()) @@ -200,12 +193,10 @@ private static RestAction actionToField(ActionRecord action, }); } - @Nonnull private static String formatTime(Instant when) { return TimeUtil.getDateTimeString(when.atOffset(ZoneOffset.UTC)); } - @Nonnull private Message attachPageTurnButtons(EmbedBuilder auditEmbed, int pageNumber, int totalPages, long guildId, long targetId, long callerId) { var messageBuilder = new MessageBuilder(auditEmbed.build()); @@ -219,7 +210,6 @@ private Message attachPageTurnButtons(EmbedBuilder auditEmbed, int pageNumber, i return messageBuilder.setActionRows(pageTurnButtons).build(); } - @Nonnull private ActionRow createPageTurnButtons(long guildId, long targetId, long callerId, int pageNumber, int totalPages) { int previousButtonTurnPageBy = -1; @@ -239,7 +229,6 @@ private ActionRow createPageTurnButtons(long guildId, long targetId, long caller return ActionRow.of(previousButton, nextButton); } - @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), 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 f633921fc9..52ee553f9b 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 @@ -19,7 +19,6 @@ 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; @@ -100,7 +99,6 @@ private static RestAction sendDm(ISnowflake target, .map(Result::isSuccess); } - @Nonnull private static MessageEmbed sendFeedback(boolean hasSentDm, User target, Member author, @Nullable ModerationUtils.TemporaryData temporaryData, String reason) { String durationText = "The ban duration is: " @@ -113,7 +111,6 @@ private static MessageEmbed sendFeedback(boolean hasSentDm, User target, Member durationText + dmNoticeText, reason); } - @Nonnull private static Optional> handleNotAlreadyBannedResponse( Throwable alreadyBannedFailure, IReplyCallback event, Guild guild, User target) { if (alreadyBannedFailure instanceof ErrorResponseException errorResponseException) { @@ -136,7 +133,6 @@ private static Optional> handleNotAlreadyBannedRespo .setEphemeral(true)); } - @Nonnull private RestAction banUserFlow(User target, Member author, @Nullable ModerationUtils.TemporaryData temporaryData, String reason, int deleteHistoryDays, Guild guild, SlashCommandInteractionEvent event) { @@ -147,7 +143,6 @@ private RestAction banUserFlow(User target, Member author, .flatMap(event::replyEmbeds); } - @Nonnull private AuditableRestAction banUser(User target, Member author, @Nullable ModerationUtils.TemporaryData temporaryData, String reason, int deleteHistoryDays, Guild guild) { 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 1b6a7e23ca..cd83762c6d 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 @@ -17,7 +17,6 @@ import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; @@ -66,7 +65,6 @@ private void kickUserFlow(Member target, Member author, String reason, Guild gui .queue(); } - @Nonnull private static RestAction sendDm(ISnowflake target, String reason, Guild guild, GenericEvent event) { return event.getJDA() @@ -82,7 +80,6 @@ private static RestAction sendDm(ISnowflake target, String reason, Guil .map(Result::isSuccess); } - @Nonnull private AuditableRestAction kickUser(Member target, Member author, String reason, Guild guild) { logger.info("'{}' ({}) kicked the user '{}' ({}) from guild '{}' for reason '{}'.", @@ -95,7 +92,6 @@ private AuditableRestAction kickUser(Member target, Member author, String return guild.kick(target, reason).reason(reason); } - @Nonnull private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, String reason) { String dmNoticeText = ""; @@ -106,7 +102,6 @@ private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Membe target.getUser(), dmNoticeText, reason); } - @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. 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 047a371300..635c69a2f1 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,7 +1,5 @@ package org.togetherjava.tjbot.commands.moderation; -import javax.annotation.Nonnull; - /** * All available moderation actions. */ @@ -62,7 +60,6 @@ public enum ModerationAction { * * @return the verb of this action */ - @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 89ffd7c231..6d6e79f456 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 @@ -5,7 +5,6 @@ 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; @@ -45,7 +44,6 @@ public ModerationActionsStore(Database database) { * * @return a list of all expired actions, chronologically ascending */ - @Nonnull public List getExpiredActionsAscending() { return getActionsAscendingWhere( ModerationActions.MODERATION_ACTIONS.ACTION_EXPIRES_AT.isNotNull() @@ -62,7 +60,6 @@ public List getExpiredActionsAscending() { * @param actionType the type of action to filter for * @return a list of all actions with the given type, chronologically ascending */ - @Nonnull public List getActionsByTypeAscending(long guildId, ModerationAction actionType) { Objects.requireNonNull(actionType); @@ -79,7 +76,6 @@ public List getActionsByTypeAscending(long guildId, ModerationActi * @param targetId the id of the target user to filter for * @return a list of all actions executed against the target, chronologically ascending */ - @Nonnull public List getActionsByTargetAscending(long guildId, long targetId) { return getActionsFromGuildAscending(guildId, ModerationActions.MODERATION_ACTIONS.TARGET_ID.eq(targetId)); @@ -94,7 +90,6 @@ public List getActionsByTargetAscending(long guildId, long targetI * @param authorId the id of the author user to filter for * @return a list of all actions executed by the author, chronologically ascending */ - @Nonnull public List getActionsByAuthorAscending(long guildId, long authorId) { return getActionsFromGuildAscending(guildId, ModerationActions.MODERATION_ACTIONS.AUTHOR_ID.eq(authorId)); @@ -110,7 +105,6 @@ public List getActionsByAuthorAscending(long guildId, long authorI * @param actionType the type of the action * @return the last action issued against the given user of the given type, if present */ - @Nonnull public Optional findLastActionAgainstTargetByType(long guildId, long targetId, ModerationAction actionType) { return database @@ -130,7 +124,6 @@ public Optional findLastActionAgainstTargetByType(long guildId, lo * @param caseId the actions' case id to search for * @return the action with the given case id, if present */ - @Nonnull public Optional findActionByCaseId(int caseId) { return database .read(context -> context.selectFrom(ModerationActions.MODERATION_ACTIONS) @@ -177,7 +170,6 @@ public int addAction(long guildId, long authorId, long targetId, ModerationActio }); } - @Nonnull private List getActionsFromGuildAscending(long guildId, Condition condition) { Objects.requireNonNull(condition); @@ -185,7 +177,6 @@ private List getActionsFromGuildAscending(long guildId, Condition ModerationActions.MODERATION_ACTIONS.GUILD_ID.eq(guildId).and(condition)); } - @Nonnull private List getActionsAscendingWhere(Condition condition) { Objects.requireNonNull(condition); 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 bf36aed4ed..b46f339767 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 @@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.config.Config; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.awt.Color; import java.time.Instant; @@ -270,7 +269,6 @@ static boolean handleHasAuthorPermissions(String actionVerb, Permission permissi * @param reason an optional reason for why the action is executed, {@code null} if not desired * @return the created response */ - @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(), @@ -305,7 +303,6 @@ public static Predicate getIsMutedRolePredicate(Config config) { * @param config the config used to identify the muted role * @return the muted role, if found */ - @Nonnull public static Optional getMutedRole(Guild guild, Config config) { Predicate isMutedRole = getIsMutedRolePredicate(config); return guild.getRoles().stream().filter(role -> isMutedRole.test(role.getName())).findAny(); @@ -328,7 +325,6 @@ public static Predicate getIsQuarantinedRolePredicate(Config config) { * @param config the config used to identify the quarantined role * @return the quarantined role, if found */ - @Nonnull public static Optional getQuarantinedRole(Guild guild, Config config) { Predicate isQuarantinedRole = getIsQuarantinedRolePredicate(config); return guild.getRoles() @@ -346,7 +342,6 @@ public static Optional getQuarantinedRole(Guild guild, Config config) { * @return the temporary data represented by the given duration or empty if the duration is * {@code "permanent"} */ - @Nonnull static Optional computeTemporaryData(String durationText) { if (PERMANENT_DURATION.equals(durationText)) { return Optional.empty(); 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 7e3f40977d..0b4e4628b8 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 @@ -15,7 +15,6 @@ 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; @@ -68,7 +67,6 @@ private static void handleAlreadyMutedTarget(IReplyCallback event) { event.reply("The user is already muted.").setEphemeral(true).queue(); } - @Nonnull private static RestAction sendDm(ISnowflake target, @Nullable ModerationUtils.TemporaryData temporaryData, String reason, Guild guild, GenericEvent event) { @@ -89,7 +87,6 @@ private static RestAction sendDm(ISnowflake target, .map(Result::isSuccess); } - @Nonnull private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, @Nullable ModerationUtils.TemporaryData temporaryData, String reason) { String durationText = "The mute duration is: " @@ -102,7 +99,6 @@ private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Membe target.getUser(), durationText + dmNoticeText, reason); } - @Nonnull private AuditableRestAction muteUser(Member target, Member author, @Nullable ModerationUtils.TemporaryData temporaryData, String reason, Guild guild) { String durationMessage = 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 73091d3c2e..c54fab71c7 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 @@ -14,7 +14,6 @@ import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; @@ -59,7 +58,6 @@ private static void handleAlreadyQuarantinedTarget(IReplyCallback event) { event.reply("The user is already quarantined.").setEphemeral(true).queue(); } - @Nonnull private static RestAction sendDm(ISnowflake target, String reason, Guild guild, GenericEvent event) { String dmMessage = @@ -78,7 +76,6 @@ private static RestAction sendDm(ISnowflake target, String reason, Guil .map(Result::isSuccess); } - @Nonnull private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, String reason) { String dmNoticeText = ""; @@ -89,7 +86,6 @@ private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Membe target.getUser(), dmNoticeText, reason); } - @Nonnull private AuditableRestAction quarantineUser(Member target, Member author, String reason, Guild guild) { logger.info("'{}' ({}) quarantined the user '{}' ({}) in guild '{}' for reason '{}'.", 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 f0414df212..72b691c8a2 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 @@ -14,7 +14,6 @@ import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; @@ -56,7 +55,6 @@ private static void handleNotMutedTarget(IReplyCallback event) { event.reply("The user is not muted.").setEphemeral(true).queue(); } - @Nonnull private static RestAction sendDm(ISnowflake target, String reason, Guild guild, GenericEvent event) { String dmMessage = """ @@ -71,7 +69,6 @@ private static RestAction sendDm(ISnowflake target, String reason, Guil .map(Result::isSuccess); } - @Nonnull private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, String reason) { String dmNoticeText = ""; @@ -82,7 +79,6 @@ private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Membe target.getUser(), dmNoticeText, reason); } - @Nonnull private AuditableRestAction unmuteUser(Member target, Member author, String reason, Guild guild) { logger.info("'{}' ({}) unmuted the user '{}' ({}) in guild '{}' for reason '{}'.", 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 117d61d5ce..87bad18f96 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 @@ -14,7 +14,6 @@ import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.config.Config; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; @@ -60,7 +59,6 @@ private static void handleNotQuarantinedTarget(IReplyCallback event) { event.reply("The user is not quarantined.").setEphemeral(true).queue(); } - @Nonnull private static RestAction sendDm(ISnowflake target, String reason, Guild guild, GenericEvent event) { String dmMessage = """ @@ -76,7 +74,6 @@ private static RestAction sendDm(ISnowflake target, String reason, Guil .map(Result::isSuccess); } - @Nonnull private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Member author, String reason) { String dmNoticeText = ""; @@ -87,7 +84,6 @@ private static MessageEmbed sendFeedback(boolean hasSentDm, Member target, Membe target.getUser(), dmNoticeText, reason); } - @Nonnull private AuditableRestAction unquarantineUser(Member target, Member author, String reason, Guild guild) { logger.info("'{}' ({}) unquarantined the user '{}' ({}) in guild '{}' for reason '{}'.", 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 a852a56728..05a6ae4fa1 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 @@ -12,7 +12,6 @@ import org.togetherjava.tjbot.commands.SlashCommandAdapter; import org.togetherjava.tjbot.commands.SlashCommandVisibility; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; @@ -44,7 +43,6 @@ public WarnCommand(ModerationActionsStore actionsStore) { this.actionsStore = Objects.requireNonNull(actionsStore); } - @Nonnull private RestAction warnUserFlow(User target, Member author, String reason, Guild guild, SlashCommandInteractionEvent event) { return dmUser(target, reason, guild, event).map(hasSentDm -> { @@ -55,7 +53,6 @@ private RestAction warnUserFlow(User target, Member author, Str .flatMap(event::replyEmbeds); } - @Nonnull private static RestAction dmUser(ISnowflake target, String reason, Guild guild, SlashCommandInteractionEvent event) { return event.getJDA() @@ -80,7 +77,6 @@ private void warnUser(User target, Member author, String reason, Guild guild) { ModerationAction.WARN, null, reason); } - @Nonnull private static MessageEmbed sendFeedback(boolean hasSentDm, User target, Member author, String reason) { String dmNoticeText = ""; 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 c54cefb97e..f255ab08ef 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 @@ -13,7 +13,6 @@ 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; @@ -70,7 +69,6 @@ public void onSlashCommand(final SlashCommandInteractionEvent event) { } @CheckReturnValue - @Nonnull private static ReplyCallbackAction handleWhoIsUser(final IReplyCallback event, final User user, final User.Profile profile) { String description = userIdentificationToStringItem(user) + "\n**Is bot:** " + user.isBot() @@ -86,7 +84,6 @@ private static ReplyCallbackAction handleWhoIsUser(final IReplyCallback event, f } @CheckReturnValue - @Nonnull private static ReplyCallbackAction handleWhoIsMember(final IReplyCallback event, final Member member, final User.Profile profile) { User user = member.getUser(); @@ -109,7 +106,6 @@ private static ReplyCallbackAction handleWhoIsMember(final IReplyCallback event, return sendEmbedWithProfileAction(event, embedBuilder.build(), user.getId()); } - @Nonnull private static ReplyCallbackAction sendEmbedWithProfileAction(final IReplyCallback event, MessageEmbed embed, String userId) { return event.replyEmbeds(embed) @@ -117,7 +113,6 @@ private static ReplyCallbackAction sendEmbedWithProfileAction(final IReplyCallba DiscordClientAction.General.USER.asLinkButton("Click to see profile!", userId)); } - @Nonnull private static String voiceStateToStringItem(final Member member) { GuildVoiceState voiceState = Objects.requireNonNull(member.getVoiceState(), "The given voiceState cannot be null"); @@ -129,7 +124,6 @@ private static String voiceStateToStringItem(final Member member) { return "\n**In voicechannel:** " + (voiceState.getChannel().getAsMention()); } - /** * Generates whois embed based on the given parameters. * @@ -139,7 +133,6 @@ private static String voiceStateToStringItem(final Member member) { * @param effectiveColor the {@link Color} that the embed will become * @return the generated {@link EmbedBuilder} */ - @Nonnull private static EmbedBuilder generateEmbedBuilder(final Interaction event, final User user, final User.Profile profile, final Color effectiveColor) { @@ -162,7 +155,6 @@ private static EmbedBuilder generateEmbedBuilder(final Interaction event, final * @param member the {@link Member} to take the booster properties from * @return user readable {@link String} */ - @Nonnull private static String possibleBoosterToStringItem(final Member member) { OffsetDateTime timeBoosted = member.getTimeBoosted(); @@ -180,7 +172,6 @@ private static String possibleBoosterToStringItem(final Member member) { * @param user the {@link User} to take the identifiers from * @return user readable {@link String} */ - @Nonnull private static String userIdentificationToStringItem(final User user) { return "**Mention:** " + user.getAsMention() + "\n**Tag:** " + user.getAsTag() + "\n**ID:** " + user.getId(); @@ -192,7 +183,6 @@ private static String userIdentificationToStringItem(final User user) { * @param member member to take the Roles from * @return user readable {@link String} of the roles */ - @Nonnull private static String formatRoles(final Member member) { return member.getRoles().stream().map(Role::getAsMention).collect(Collectors.joining(", ")); } @@ -204,7 +194,6 @@ private static String formatRoles(final Member member) { * (recommend {@link java.util.EnumSet} * @return user readable {@link StringBuilder} */ - @Nonnull private static StringBuilder userFlagsToStringItem(final Collection flags) { String formattedFlags = formatUserFlags(flags); StringBuilder result = hypeSquadToStringItem(flags); @@ -223,7 +212,6 @@ private static StringBuilder userFlagsToStringItem(final Collection flags) { StringBuilder stringBuilder = new StringBuilder("**\nHypesquad:** "); @@ -247,7 +235,6 @@ private static StringBuilder hypeSquadToStringItem(final Collection flags) { return flags.stream() .map(User.UserFlag::getName) diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/moderation/attachment/BlacklistedAttachmentListener.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/attachment/BlacklistedAttachmentListener.java new file mode 100644 index 0000000000..e2e56d684e --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/attachment/BlacklistedAttachmentListener.java @@ -0,0 +1,113 @@ +package org.togetherjava.tjbot.commands.moderation.attachment; + +import net.dv8tion.jda.api.EmbedBuilder; +import net.dv8tion.jda.api.MessageBuilder; +import net.dv8tion.jda.api.entities.Message; +import net.dv8tion.jda.api.entities.MessageEmbed; +import net.dv8tion.jda.api.events.message.MessageReceivedEvent; +import net.dv8tion.jda.api.requests.RestAction; +import org.togetherjava.tjbot.commands.MessageReceiverAdapter; +import org.togetherjava.tjbot.config.Config; +import org.togetherjava.tjbot.moderation.ModAuditLogWriter; + +import java.awt.Color; +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; + +/** + * Reacts to blacklisted attachments being posted, upon which they are deleted. + */ +public final class BlacklistedAttachmentListener extends MessageReceiverAdapter { + private final ModAuditLogWriter modAuditLogWriter; + private final List blacklistedFileExtensions; + + /** + * Creates a AttachmentListener to receive all message sent in any channel. + * + * @param config to find the blacklisted media attachments + * @param modAuditLogWriter to inform the mods about the suspicious attachment + */ + public BlacklistedAttachmentListener(Config config, ModAuditLogWriter modAuditLogWriter) { + super(Pattern.compile(".*")); + this.modAuditLogWriter = modAuditLogWriter; + blacklistedFileExtensions = config.getBlacklistedFileExtensions(); + } + + @Override + public void onMessageReceived(MessageReceivedEvent event) { + if (event.getAuthor().isBot() || event.isWebhookMessage()) { + return; + } + if (doesMessageContainBlacklistedContent(event.getMessage())) { + handleBadMessage(event.getMessage()); + } + } + + private void handleBadMessage(Message message) { + message.delete().flatMap(any -> dmUser(message)).queue(any -> warnMods(message)); + } + + private RestAction dmUser(Message message) { + Message dmMessage = createDmMessage(message); + return message.getAuthor() + .openPrivateChannel() + .flatMap(privateChannel -> privateChannel.sendMessage(dmMessage)); + } + + private Message createDmMessage(Message originalMessage) { + String contentRaw = originalMessage.getContentRaw(); + String blacklistedAttachments = + String.join(", ", getBlacklistedAttachmentsFromMessage(originalMessage)); + + String dmMessageContent = + """ + Hey there, you posted a message containing a blacklisted file attachment: %s. + We had to delete your message for security reasons. + + Feel free to repost your message without, or with a different file instead. Sorry for any inconvenience caused by this πŸ™‡οΈ + """ + .formatted(blacklistedAttachments); + + // No embed needed if there was no message from the user + if (contentRaw.isEmpty()) { + return new MessageBuilder(dmMessageContent).build(); + } + return createBaseResponse(contentRaw, dmMessageContent); + } + + private Message createBaseResponse(String originalMessageContent, String dmMessageContent) { + MessageEmbed originalMessageEmbed = + new EmbedBuilder().setDescription(originalMessageContent) + .setColor(Color.ORANGE) + .build(); + return new MessageBuilder(dmMessageContent).setEmbeds(originalMessageEmbed).build(); + } + + private List getBlacklistedAttachmentsFromMessage(Message originalMessage) { + return originalMessage.getAttachments() + .stream() + .filter(attachment -> blacklistedFileExtensions + .contains(attachment.getFileExtension().toLowerCase(Locale.US))) + .map(Message.Attachment::getFileName) + .toList(); + } + + private boolean doesMessageContainBlacklistedContent(Message message) { + return message.getAttachments() + .stream() + .anyMatch(attachment -> blacklistedFileExtensions + .contains(attachment.getFileExtension().toLowerCase(Locale.US))); + } + + private void warnMods(Message sentUserMessage) { + String blacklistedAttachmentsFromMessage = + String.join(", ", getBlacklistedAttachmentsFromMessage(sentUserMessage)); + + modAuditLogWriter.write( + "Message with blacklisted content prevented: %s" + .formatted(blacklistedAttachmentsFromMessage), + "Sent Message: %s".formatted(sentUserMessage), sentUserMessage.getAuthor(), + sentUserMessage.getTimeCreated(), sentUserMessage.getGuild()); + } +} 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 779ef299a7..56ce69483b 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,7 +2,10 @@ * This package offers all the moderation commands from the application such as banning and kicking * users. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.moderation; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 7c1e812d0d..e488c34387 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 @@ -26,7 +26,6 @@ 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.*; @@ -84,7 +83,6 @@ public ScamBlocker(ModerationActionsStore actionsStore, ScamHistoryStore scamHis } @Override - @Nonnull public String getName() { return "scam-blocker"; } @@ -250,12 +248,10 @@ If you think this was a mistake (for example, your account was hacked, but you g .queue(); } - @Nonnull private Optional getReportChannel(Guild guild) { return guild.getTextChannelCache().stream().filter(isReportChannel).findAny(); } - @Nonnull private ActionRow createConfirmDialog(MessageReceivedEvent event) { ComponentIdArguments args = new ComponentIdArguments(mode, event.getGuild().getIdLong(), event.getChannel().getIdLong(), event.getMessageIdLong(), @@ -266,7 +262,6 @@ private ActionRow createConfirmDialog(MessageReceivedEvent event) { Button.danger(generateComponentId(args), "No")); } - @Nonnull private String generateComponentId(ComponentIdArguments args) { return Objects.requireNonNull(componentIdGenerator) .generate(new ComponentId(getName(), args.toList()), Lifespan.REGULAR); @@ -334,11 +329,9 @@ public void onButtonClick(ButtonInteractionEvent event, List argsRaw) { .queue(onRetrieveAuthorSuccess, onRetrieveAuthorFailure); } - private record ComponentIdArguments(ScamBlockerConfig.Mode mode, long guildId, long channelId, long messageId, long authorId, String contentHash) { - @Nonnull static ComponentIdArguments fromList(List args) { ScamBlockerConfig.Mode mode = ScamBlockerConfig.Mode.valueOf(args.get(0)); long guildId = Long.parseLong(args.get(1)); @@ -350,7 +343,6 @@ static ComponentIdArguments fromList(List args) { contentHash); } - @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/ScamHistoryPurgeRoutine.java b/application/src/main/java/org/togetherjava/tjbot/commands/moderation/scam/ScamHistoryPurgeRoutine.java index 6c6ed71de9..e776aa4293 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 @@ -3,7 +3,6 @@ import net.dv8tion.jda.api.JDA; import org.togetherjava.tjbot.commands.Routine; -import javax.annotation.Nonnull; import java.time.Instant; import java.time.Period; import java.util.concurrent.TimeUnit; @@ -25,7 +24,6 @@ public ScamHistoryPurgeRoutine(ScamHistoryStore scamHistoryStore) { } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, 1, TimeUnit.DAYS); } 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 9f1802610b..3047bd177c 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 @@ -6,7 +6,6 @@ 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; @@ -71,7 +70,6 @@ public void addScam(Message scam, boolean isDeleted) { * @return identifications of all scam messages that have just been marked deleted, which * previously have not been marked accordingly yet */ - @Nonnull public Collection markScamDuplicatesDeleted(Message scam) { return markScamDuplicatesDeleted(scam.getGuild().getIdLong(), scam.getAuthor().getIdLong(), hashMessageContent(scam)); @@ -87,7 +85,6 @@ public Collection markScamDuplicatesDeleted(Message scam) { * @return identifications of all scam messages that have just been marked deleted, which * previously have not been marked accordingly yet */ - @Nonnull public Collection markScamDuplicatesDeleted(long guildId, long authorId, String contentHash) { return database.writeAndProvide(context -> { @@ -139,7 +136,6 @@ public void deleteHistoryOlderThan(Instant olderThan) { * @param message the message to hash * @return a text representation of the hash */ - @Nonnull public static String hashMessageContent(Message message) { return Hashing.bytesToHex(Hashing.hash(HASH_METHOD, message.getContentRaw().getBytes(StandardCharsets.UTF_8))); @@ -156,7 +152,6 @@ public static String hashMessageContent(Message message) { */ public record ScamIdentification(long guildId, long channelId, long messageId, long authorId, String contentHash) { - @Nonnull private static ScamIdentification ofDatabaseRecord(ScamHistoryRecord scamHistoryRecord) { return new ScamIdentification(scamHistoryRecord.getGuildId(), scamHistoryRecord.getChannelId(), scamHistoryRecord.getMessageId(), 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 2cf89b16e6..77bb00fedd 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,7 +2,10 @@ * 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. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.moderation.scam; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 b74290afd1..69c52870da 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 @@ -5,8 +5,6 @@ import net.dv8tion.jda.api.requests.RestAction; 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. @@ -35,7 +33,6 @@ enum FailureIdentification { * * @return the type to apply the temporary action */ - @Nonnull ModerationAction getApplyType(); /** @@ -44,7 +41,6 @@ enum FailureIdentification { * * @return the type to revoke the temporary action */ - @Nonnull ModerationAction getRevokeType(); /** @@ -55,7 +51,6 @@ enum FailureIdentification { * @param reason why the action is revoked * @return the unsubmitted revocation action */ - @Nonnull RestAction revokeAction(Guild guild, User target, String reason); /** @@ -67,6 +62,5 @@ enum FailureIdentification { * @return a classification of the failure, decides whether the surrounding flow will continue * to handle the error further or not */ - @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 bb7094f3a2..1e5e61b7e4 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 @@ -4,8 +4,6 @@ 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. @@ -26,7 +24,6 @@ abstract class RevocableRoleBasedAction implements RevocableModerationAction { } @Override - @Nonnull public FailureIdentification handleRevokeFailure(Throwable failure, long targetId) { if (failure instanceof ErrorResponseException errorResponseException) { 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 eaa42e34c9..1e6cdb779a 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 @@ -9,8 +9,6 @@ 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 @@ -20,25 +18,21 @@ final class TemporaryBanAction implements RevocableModerationAction { private static final Logger logger = LoggerFactory.getLogger(TemporaryBanAction.class); @Override - @Nonnull public ModerationAction getApplyType() { return ModerationAction.BAN; } @Override - @Nonnull public ModerationAction getRevokeType() { return ModerationAction.UNBAN; } @Override - @Nonnull public RestAction revokeAction(Guild guild, User target, String reason) { return guild.unban(target).reason(reason); } @Override - @Nonnull public FailureIdentification handleRevokeFailure(Throwable failure, long targetId) { if (failure instanceof ErrorResponseException errorResponseException) { if (errorResponseException.getErrorResponse() == ErrorResponse.UNKNOWN_USER) { 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 34df11d906..0cf42e45cd 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 @@ -12,7 +12,6 @@ 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; @@ -60,7 +59,6 @@ public void runRoutine(JDA jda) { } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_DELAY, 5, 5, TimeUnit.MINUTES); } @@ -123,7 +121,6 @@ private void revokeAction(RevocationGroupIdentifier groupIdentifier) { }, failure -> handleFailure(failure, groupIdentifier)); } - @Nonnull private RestAction executeRevocation(Guild guild, User target, ModerationAction actionType) { logger.info("Revoked temporary action {} against user '{}' ({}).", actionType, @@ -148,7 +145,6 @@ private void handleFailure(Throwable failure, RevocationGroupIdentifier groupIde groupIdentifier.targetId, failure); } - @Nonnull private RevocableModerationAction getRevocableActionByType(ModerationAction type) { return Objects.requireNonNull(typeToRevocableAction.get(type), "Action type is not revocable: " + type); 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 94afeb2948..aa1a40e096 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 @@ -7,8 +7,6 @@ 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 @@ -29,19 +27,16 @@ final class TemporaryMuteAction extends RevocableRoleBasedAction { } @Override - @Nonnull public ModerationAction getApplyType() { return ModerationAction.MUTE; } @Override - @Nonnull public ModerationAction getRevokeType() { return ModerationAction.UNMUTE; } @Override - @Nonnull public RestAction revokeAction(Guild guild, User target, String reason) { return guild .removeRoleFromMember(target.getIdLong(), 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 67393450f3..ca44ddc746 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 @@ -7,8 +7,6 @@ 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 @@ -29,19 +27,16 @@ final class TemporaryQuarantineAction extends RevocableRoleBasedAction { } @Override - @Nonnull public ModerationAction getApplyType() { return ModerationAction.QUARANTINE; } @Override - @Nonnull public ModerationAction getRevokeType() { return ModerationAction.UNQUARANTINE; } @Override - @Nonnull public RestAction revokeAction(Guild guild, User target, String reason) { return guild .removeRoleFromMember(target.getIdLong(), 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 6a11e771d2..bb89723144 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,7 +1,10 @@ /** * This package offers classes dealing with temporary moderation actions, such as temporary bans. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.moderation.temp; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 0a00d8bf03..0029166d7e 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,7 +9,10 @@ * {@link org.togetherjava.tjbot.commands.SlashCommand} or using the adapter * {@link org.togetherjava.tjbot.commands.SlashCommandAdapter} for convenience. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 513e72438a..931b26e075 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 @@ -11,7 +11,6 @@ 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; @@ -102,7 +101,6 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { .insert()); } - @Nonnull private static Instant parseWhen(int whenAmount, String whenUnit) { TemporalAmount period = switch (whenUnit) { case "second", "seconds" -> Duration.ofSeconds(whenAmount); 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 c755fe0974..621cbdce73 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 @@ -13,7 +13,6 @@ import org.togetherjava.tjbot.commands.Routine; import org.togetherjava.tjbot.db.Database; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.awt.Color; import java.time.Instant; @@ -45,7 +44,6 @@ public RemindRoutine(Database database) { } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, SCHEDULE_INTERVAL_SECONDS, TimeUnit.SECONDS); @@ -84,7 +82,6 @@ private static RestAction computeReminderRoute(JDA jda, long chan return createDmReminderRoute(jda, authorId); } - @Nonnull private static RestAction createGuildReminderRoute(JDA jda, long authorId, MessageChannel channel) { return jda.retrieveUserById(authorId) @@ -92,7 +89,6 @@ private static RestAction createGuildReminderRoute(JDA jda, long .map(author -> ReminderRoute.toPublic(channel, author)); } - @Nonnull private static RestAction createDmReminderRoute(JDA jda, long authorId) { return jda.openPrivateChannelById(authorId).map(ReminderRoute::toPrivate); } @@ -113,7 +109,6 @@ Failed to send a reminder (id '{}'), skipping it. This can be due to a network i routeAction.flatMap(sendMessage).queue(doNothing(), logFailure); } - @Nonnull private static MessageEmbed createReminderEmbed(CharSequence content, TemporalAccessor createdAt, @Nullable User author) { String authorName = author == null ? "Unknown user" : author.getAsTag(); @@ -127,7 +122,6 @@ private static MessageEmbed createReminderEmbed(CharSequence content, .build(); } - @Nonnull private static Consumer doNothing() { return a -> { }; @@ -135,13 +129,11 @@ private static Consumer doNothing() { private record ReminderRoute(MessageChannel channel, @Nullable User target, @Nullable String description) { - @Nonnull static ReminderRoute toPublic(MessageChannel channel, @Nullable User target) { return new ReminderRoute(channel, target, target == null ? null : target.getAsMention()); } - @Nonnull static ReminderRoute toPrivate(PrivateChannel channel) { return new ReminderRoute(channel, channel.getUser(), "(Sending your reminder directly, because I was unable to locate" 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 f4fab40923..5aafa9946f 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,7 +2,10 @@ * This packages offers all the functionality for the remind-command. The core class is * {@link org.togetherjava.tjbot.commands.reminder.RemindCommand}. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.reminder; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 f7eae74609..51e9434eed 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 @@ -25,7 +25,6 @@ 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; @@ -125,7 +124,6 @@ public BotCore(JDA jda, Database database, Config config) { } @Override - @Nonnull public Collection getSlashCommands() { return nameToInteractor.values() .stream() @@ -135,7 +133,6 @@ public Collection getSlashCommands() { } @Override - @Nonnull public Optional getSlashCommand(String name) { return Optional.ofNullable(nameToInteractor.get(name)) .filter(SlashCommand.class::isInstance) @@ -204,7 +201,6 @@ public void onMessageUpdate(final MessageUpdateEvent event) { } } - @Nonnull private Stream getMessageReceiversSubscribedTo(Channel channel) { String channelName = channel.getName(); return channelNameToMessageReceiver.entrySet() @@ -308,7 +304,6 @@ private void forwardComponentCommand(T event, * @return the command with the given name * @throws NullPointerException if the command with the given name was not registered */ - @Nonnull private SlashCommand requireSlashCommand(String name) { return getSlashCommand(name).orElseThrow( () -> new NullPointerException("There is no slash command with name " + name)); @@ -321,7 +316,6 @@ private SlashCommand requireSlashCommand(String name) { * @return the user interactor with the given name * @throws NullPointerException if the user interactor with the given name was not registered */ - @Nonnull private UserInteractor requireUserInteractor(String name) { return Objects.requireNonNull(nameToInteractor.get(name)); } 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 1b715aad28..f061b98695 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 @@ -17,7 +17,6 @@ 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; @@ -132,7 +131,6 @@ public void onButtonClick(ButtonInteractionEvent event, List args) { * @param updateAction the upstream to update commands * @return the given upstream for chaining */ - @Nonnull private CommandListUpdateAction updateCommandsIf(Predicate commandFilter, CommandListUpdateAction updateAction) { return commandProvider.getSlashCommands() @@ -142,12 +140,10 @@ private CommandListUpdateAction updateCommandsIf(Predicate .reduce(updateAction, CommandListUpdateAction::addCommands, (x, y) -> x); } - @Nonnull private static CommandListUpdateAction getGlobalUpdateAction(JDA jda) { return jda.updateCommands(); } - @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 85cc662511..64808d67f4 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 @@ -2,7 +2,6 @@ import org.togetherjava.tjbot.commands.SlashCommand; -import javax.annotation.Nonnull; import java.util.Collection; import java.util.Optional; @@ -15,7 +14,6 @@ public interface SlashCommandProvider { * * @return all slash commands */ - @Nonnull Collection getSlashCommands(); /** @@ -24,6 +22,5 @@ public interface SlashCommandProvider { * @param name the name of the command * @return the command registered under this name, if any */ - @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 48e796b587..92087eae83 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,7 +2,10 @@ * This package represents the core of the command system. The entry point is * {@link org.togetherjava.tjbot.commands.system.BotCore}. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.system; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; 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 9b34c08a12..c7b2602da2 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 @@ -16,7 +16,6 @@ import org.togetherjava.tjbot.commands.SlashCommandVisibility; import org.togetherjava.tjbot.moderation.ModAuditLogWriter; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.nio.charset.StandardCharsets; import java.time.Instant; @@ -123,7 +122,6 @@ private static void sendSuccessMessage(IReplyCallback event, String id, String a * @param event the event to send messages with * @return the parsed message id, if successful */ - @Nonnull private static OptionalLong parseMessageIdAndHandle(String messageId, IReplyCallback event) { try { return OptionalLong.of(Long.parseLong(messageId)); @@ -289,7 +287,6 @@ private void handleActionWithMessage(TagStatus requiredTagStatus, * @param id the id of the tag to get its content * @return the content of the tag, if present */ - @Nonnull private Optional getTagContent(Subcommand subcommand, String id) { if (Subcommand.SUBCOMMANDS_WITH_PREVIOUS_CONTENT.contains(subcommand)) { try { @@ -383,7 +380,6 @@ private enum TagStatus { NOT_EXISTS } - enum Subcommand { RAW("raw", ""), CREATE("create", "created"), @@ -397,7 +393,6 @@ enum Subcommand { private static final Set SUBCOMMANDS_WITH_PREVIOUS_CONTENT = EnumSet.of(EDIT, EDIT_WITH_MESSAGE, DELETE); - private final String name; private final String actionVerb; @@ -406,12 +401,10 @@ enum Subcommand { this.actionVerb = actionVerb; } - @Nonnull String getName() { return name; } - @Nonnull static Subcommand fromName(String name) { for (Subcommand subcommand : Subcommand.values()) { if (subcommand.name.equals(name)) { @@ -422,7 +415,6 @@ static Subcommand fromName(String name) { "Subcommand with name '%s' is unknown".formatted(name)); } - @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 13272b6131..8a34131be9 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 @@ -9,7 +9,6 @@ import org.togetherjava.tjbot.db.generated.tables.Tags; import org.togetherjava.tjbot.db.generated.tables.records.TagsRecord; -import javax.annotation.Nonnull; import java.awt.Color; import java.util.Optional; import java.util.Set; @@ -122,7 +121,6 @@ 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,7 +132,6 @@ 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/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/tags/package-info.java index 41eb96651e..674fd1fce4 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,7 +4,10 @@ * like {@link org.togetherjava.tjbot.commands.tags.TagCommand} as entry point to the package's * offered functionality. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.tags; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 5556384cfe..dd609826ea 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 @@ -18,7 +18,6 @@ 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.*; @@ -88,7 +87,6 @@ public void onSlashCommand(SlashCommandInteractionEvent event) { .onSuccess(members -> handleTopHelpers(topHelpers, members, timeRange, event)); } - @Nonnull private static Month computeMonth(@Nullable OptionMapping atMonthData) { if (atMonthData != null) { return Month.valueOf(atMonthData.getAsString()); @@ -98,7 +96,6 @@ private static Month computeMonth(@Nullable OptionMapping atMonthData) { return Instant.now().atZone(ZoneOffset.UTC).minusMonths(1).getMonth(); } - @Nonnull private static TimeRange computeTimeRange(Month atMonth) { ZonedDateTime now = Instant.now().atZone(ZoneOffset.UTC); @@ -117,7 +114,6 @@ private static TimeRange computeTimeRange(Month atMonth) { return new TimeRange(start, end, description); } - @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)) @@ -151,7 +147,6 @@ private static void handleTopHelpers(Collection topHelpers, event.getHook().editOriginal(message).queue(); } - @Nonnull private static List topHelperToDataRow(TopHelperResult topHelper, @Nullable Member member) { String id = Long.toString(topHelper.authorId()); @@ -161,7 +156,6 @@ private static List topHelperToDataRow(TopHelperResult topHelper, return List.of(id, name, messageLengths); } - @Nonnull private static String dataTableToString(Collection> dataTable, TimeRange timeRange) { return dataTableToAsciiTable(dataTable, @@ -172,7 +166,6 @@ private static String dataTableToString(Collection> dataTable, HorizontalAlign.RIGHT))); } - @Nonnull private static String dataTableToAsciiTable(Collection> dataTable, List columnSettings) { IntFunction headerToAlignment = i -> columnSettings.get(i).headerName(); @@ -192,11 +185,9 @@ private static String dataTableToAsciiTable(Collection> dataTable, private record TimeRange(Instant start, Instant end, String description) { } - private record TopHelperResult(long authorId, BigDecimal messageLengths) { } - private record ColumnSetting(String headerName, HorizontalAlign alignment) { } } 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 a685f1af18..49d2e55d41 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 @@ -6,7 +6,6 @@ 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; @@ -33,7 +32,6 @@ public TopHelpersPurgeMessagesRoutine(Database database) { } @Override - @Nonnull public Schedule createSchedule() { return new Schedule(ScheduleMode.FIXED_RATE, 0, 4, TimeUnit.HOURS); } 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 224148b934..042aef8901 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,7 +2,10 @@ * This packages offers all the functionality for the top-helpers command system. The core class is * {@link org.togetherjava.tjbot.commands.tophelper.TopHelpersCommand}. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.tophelper; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + 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 0f98a3da4a..7a60dd9604 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 @@ -4,7 +4,6 @@ import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle; import org.jetbrains.annotations.Contract; -import javax.annotation.Nonnull; import java.util.regex.Pattern; /** @@ -82,7 +81,6 @@ public enum Guild { public static final DiscordClientAction GUILDS_CREATE = new DiscordClientAction("discord://-/guilds/create"); - public static final DiscordClientAction GUILD_EVENT = new DiscordClientAction("discord://-/events/{GUILD-ID}/{EVENT-ID}"); public static final DiscordClientAction GUILD_MEMBERSHIP_SCREENING = @@ -261,7 +259,6 @@ public String getRawUrl() { * @return The formatted URL as an {@link String} * @throws IllegalArgumentException When missing arguments */ - @Nonnull public String formatUrl(final String... arguments) { String localUrl = url; @@ -285,13 +282,11 @@ public String formatUrl(final String... arguments) { * @return A {@link Button} of {@link ButtonStyle#LINK} with the given label * @throws IllegalArgumentException When missing 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 6b63de1120..2551259e6b 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,6 +1,5 @@ package org.togetherjava.tjbot.commands.utils; -import javax.annotation.Nonnull; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -25,7 +24,6 @@ private Hashing() { * @param bytes the binary data to convert * @return a hexadecimal representation */ - @Nonnull public static String bytesToHex(byte[] bytes) { Objects.requireNonNull(bytes); // See https://stackoverflow.com/a/9855338/2411243 @@ -50,7 +48,6 @@ public static String bytesToHex(byte[] bytes) { * @param data the data to hash * @return the computed hash */ - @Nonnull public static byte[] hash(String method, byte[] data) { Objects.requireNonNull(method); Objects.requireNonNull(data); 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 c14a667fe0..10e8436763 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 @@ -5,7 +5,6 @@ import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.utils.MarkdownSanitizer; -import javax.annotation.Nonnull; import java.util.List; /** @@ -39,7 +38,6 @@ public static void disableButtons(Message message) { .queue(); } - /** * Escapes every markdown content in the given string. * @@ -48,7 +46,6 @@ public static void disableButtons(Message message) { * @param text the text to escape * @return the escaped text */ - @Nonnull public static String escapeMarkdown(String text) { // NOTE Unfortunately the utility does not escape backslashes '\', so we have to do it // ourselves diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/utils/StringDistances.java b/application/src/main/java/org/togetherjava/tjbot/commands/utils/StringDistances.java index 5db2a5be0d..c839a46681 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/utils/StringDistances.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/utils/StringDistances.java @@ -1,6 +1,5 @@ package org.togetherjava.tjbot.commands.utils; -import javax.annotation.Nonnull; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; @@ -27,7 +26,6 @@ private StringDistances() { * @param the type of the candidates * @return the best matching candidate, or empty iff the candidates are empty */ - @Nonnull public static Optional closestMatch(CharSequence query, Collection candidates) { return candidates.stream() @@ -47,7 +45,6 @@ public static Optional closestMatch(CharSequence que * @param the type of the candidates * @return the best matching candidate, or empty iff the candidates are empty */ - @Nonnull public static Optional autocomplete(CharSequence prefix, Collection candidates) { return candidates.stream() @@ -110,7 +107,6 @@ public static int prefixEditDistance(CharSequence source, CharSequence destinati * @param destination the destination string to receive by editing the source * @return the levenshtein distance table */ - @Nonnull private static int[][] computeLevenshteinDistanceTable(CharSequence source, CharSequence destination) { int rows = source.length() + 1; diff --git a/application/src/main/java/org/togetherjava/tjbot/commands/utils/package-info.java b/application/src/main/java/org/togetherjava/tjbot/commands/utils/package-info.java index 9fe66765e6..be1f45fd42 100644 --- a/application/src/main/java/org/togetherjava/tjbot/commands/utils/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/commands/utils/package-info.java @@ -1,7 +1,10 @@ /** * This package contains general utility used by commands. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.commands.utils; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/config/Config.java b/application/src/main/java/org/togetherjava/tjbot/config/Config.java index 6bc43ec68e..1b3eb5d634 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/Config.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/Config.java @@ -5,9 +5,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import javax.annotation.Nonnull; import java.io.IOException; import java.nio.file.Path; +import java.util.Collections; +import java.util.List; /** * Configuration of the application. Create instances using {@link #load(Path)}. @@ -28,6 +29,7 @@ public final class Config { private final ScamBlockerConfig scamBlocker; private final String wolframAlphaAppId; private final HelpSystemConfig helpSystem; + private final List blacklistedFileExtension; private final String mediaOnlyChannelPattern; @@ -48,7 +50,8 @@ private Config(@JsonProperty("token") String token, @JsonProperty("scamBlocker") ScamBlockerConfig scamBlocker, @JsonProperty("wolframAlphaAppId") String wolframAlphaAppId, @JsonProperty("helpSystem") HelpSystemConfig helpSystem, - @JsonProperty("mediaOnlyChannelPattern") String mediaOnlyChannelPattern) { + @JsonProperty("mediaOnlyChannelPattern") String mediaOnlyChannelPattern, + @JsonProperty("blacklistedFileExtension") List blacklistedFileExtension) { this.token = token; this.gistApiKey = gistApiKey; this.databasePath = databasePath; @@ -65,6 +68,7 @@ private Config(@JsonProperty("token") String token, this.wolframAlphaAppId = wolframAlphaAppId; this.helpSystem = helpSystem; this.mediaOnlyChannelPattern = mediaOnlyChannelPattern; + this.blacklistedFileExtension = blacklistedFileExtension; } /** @@ -181,7 +185,6 @@ public String getTagManageRolePattern() { * * @return the suggestion system config */ - @Nonnull public SuggestionsConfig getSuggestions() { return suggestions; } @@ -191,7 +194,6 @@ public SuggestionsConfig getSuggestions() { * * @return the role name pattern */ - @Nonnull public String getQuarantinedRolePattern() { return quarantinedRolePattern; } @@ -201,7 +203,6 @@ public String getQuarantinedRolePattern() { * * @return the scam blocker system config */ - @Nonnull public ScamBlockerConfig getScamBlocker() { return scamBlocker; } @@ -211,7 +212,6 @@ public ScamBlockerConfig getScamBlocker() { * * @return the application ID for the WolframAlpha API */ - @Nonnull public String getWolframAlphaAppId() { return wolframAlphaAppId; } @@ -221,7 +221,6 @@ public String getWolframAlphaAppId() { * * @return the help system config */ - @Nonnull public HelpSystemConfig getHelpSystem() { return helpSystem; } @@ -231,8 +230,16 @@ public HelpSystemConfig getHelpSystem() { * * @return the channel name pattern */ - @Nonnull public String getMediaOnlyChannelPattern() { return mediaOnlyChannelPattern; } + + /** + * Gets a list of all blacklisted file extensions. + * + * @return a list of all blacklisted file extensions + */ + public List getBlacklistedFileExtensions() { + return Collections.unmodifiableList(blacklistedFileExtension); + } } diff --git a/application/src/main/java/org/togetherjava/tjbot/config/HelpSystemConfig.java b/application/src/main/java/org/togetherjava/tjbot/config/HelpSystemConfig.java index c4708e6f3e..4d001adfbc 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/HelpSystemConfig.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/HelpSystemConfig.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRootName; -import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -37,7 +36,6 @@ private HelpSystemConfig(@JsonProperty("stagingChannelPattern") String stagingCh * * @return the channel name pattern */ - @Nonnull public String getStagingChannelPattern() { return stagingChannelPattern; } @@ -48,7 +46,6 @@ public String getStagingChannelPattern() { * * @return the channel name pattern */ - @Nonnull public String getOverviewChannelPattern() { return overviewChannelPattern; } @@ -58,7 +55,6 @@ public String getOverviewChannelPattern() { * * @return a list of all categories */ - @Nonnull public List getCategories() { return Collections.unmodifiableList(categories); } @@ -73,7 +69,6 @@ public List getCategories() { * * @return the suffix */ - @Nonnull public String getCategoryRoleSuffix() { return categoryRoleSuffix; } diff --git a/application/src/main/java/org/togetherjava/tjbot/config/ScamBlockerConfig.java b/application/src/main/java/org/togetherjava/tjbot/config/ScamBlockerConfig.java index 8e581f1c92..2de5d29d1a 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/ScamBlockerConfig.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/ScamBlockerConfig.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonRootName; -import javax.annotation.Nonnull; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -53,7 +52,6 @@ public Mode getMode() { * * @return the channel name pattern */ - @Nonnull public String getReportChannelPattern() { return reportChannelPattern; } @@ -63,7 +61,6 @@ public String getReportChannelPattern() { * * @return the whitelist of hosts */ - @Nonnull public Set getHostWhitelist() { return Collections.unmodifiableSet(hostWhitelist); } @@ -73,7 +70,6 @@ public Set getHostWhitelist() { * * @return the blacklist of hosts */ - @Nonnull public Set getHostBlacklist() { return Collections.unmodifiableSet(hostBlacklist); } @@ -84,7 +80,6 @@ public Set getHostBlacklist() { * * @return the set of suspicious host keywords */ - @Nonnull public Set getSuspiciousHostKeywords() { return Collections.unmodifiableSet(suspiciousHostKeywords); } diff --git a/application/src/main/java/org/togetherjava/tjbot/config/package-info.java b/application/src/main/java/org/togetherjava/tjbot/config/package-info.java index 6d5dc89e27..80a4821450 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/package-info.java @@ -2,7 +2,10 @@ * This package contains the configuration of the application. It revolves around the class * {@link org.togetherjava.tjbot.config.Config}. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.config; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/logging/FlaggedFilter.java b/application/src/main/java/org/togetherjava/tjbot/logging/FlaggedFilter.java index f48359c327..844c90a24f 100644 --- a/application/src/main/java/org/togetherjava/tjbot/logging/FlaggedFilter.java +++ b/application/src/main/java/org/togetherjava/tjbot/logging/FlaggedFilter.java @@ -8,9 +8,6 @@ import org.apache.logging.log4j.core.config.plugins.PluginFactory; import org.apache.logging.log4j.core.filter.AbstractFilter; -import javax.annotation.Nonnull; - - /** * A custom Filter for Log4j2, which only lets an event pass through if a Logging Flag is set in the * environment. Intended to be used for local development for devs do not want to also run the @@ -44,7 +41,6 @@ public FlaggedFilter(Result onMatch, Result onMismatch) { * @return {@link Result#DENY} if the Flag is not set, else {@link Result#NEUTRAL} */ @Override - @Nonnull public Result filter(LogEvent event) { return isLoggingEnabled() ? Result.NEUTRAL : Result.DENY; } @@ -61,7 +57,6 @@ boolean isLoggingEnabled() { * @return The created FlaggedFilter. */ @PluginFactory - @Nonnull public static FlaggedFilter createFilter( @PluginAttribute(value = "onMatch", defaultString = "NEUTRAL") Result onMatch, diff --git a/application/src/main/java/org/togetherjava/tjbot/logging/package-info.java b/application/src/main/java/org/togetherjava/tjbot/logging/package-info.java index 3c63553cd1..59352946d3 100644 --- a/application/src/main/java/org/togetherjava/tjbot/logging/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/logging/package-info.java @@ -1,7 +1,10 @@ /** * This package is for custom logging plugins of the bot. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.logging; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/moderation/ModAuditLogWriter.java b/application/src/main/java/org/togetherjava/tjbot/moderation/ModAuditLogWriter.java index 1d758dd3af..d300031d23 100644 --- a/application/src/main/java/org/togetherjava/tjbot/moderation/ModAuditLogWriter.java +++ b/application/src/main/java/org/togetherjava/tjbot/moderation/ModAuditLogWriter.java @@ -10,7 +10,6 @@ import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.config.Config; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.awt.Color; import java.io.File; @@ -88,7 +87,6 @@ public void write(String title, String description, @Nullable User author, * @param guild the guild to look for the channel in * @return the channel used for moderation audit logs, if present */ - @Nonnull public Optional getAndHandleModAuditLogChannel(Guild guild) { Optional auditLogChannel = guild.getTextChannelCache() .stream() @@ -116,7 +114,6 @@ public record Attachment(String name, String content) { * * @return the raw content of the attachment */ - @Nonnull public byte[] getContentRaw() { return content.getBytes(StandardCharsets.UTF_8); } diff --git a/application/src/main/java/org/togetherjava/tjbot/package-info.java b/application/src/main/java/org/togetherjava/tjbot/package-info.java index 4f380e7377..4989de1a8c 100644 --- a/application/src/main/java/org/togetherjava/tjbot/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/package-info.java @@ -1,7 +1,10 @@ /** * Entry package for the TJ-Bot. See {@link org.togetherjava.tjbot.Application} to get started. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/main/java/org/togetherjava/tjbot/routines/ModAuditLogRoutine.java b/application/src/main/java/org/togetherjava/tjbot/routines/ModAuditLogRoutine.java index 8ae82da6f4..7f4b6c5de0 100644 --- a/application/src/main/java/org/togetherjava/tjbot/routines/ModAuditLogRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/routines/ModAuditLogRoutine.java @@ -20,7 +20,6 @@ import org.togetherjava.tjbot.db.generated.tables.ModAuditLogGuildProcess; import org.togetherjava.tjbot.moderation.ModAuditLogWriter; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.awt.Color; import java.time.*; @@ -65,7 +64,6 @@ public ModAuditLogRoutine(Database database, Config config, this.modAuditLogWriter = modAuditLogWriter; } - @Nonnull private static RestAction handleAction(Action action, AuditLogEntry entry) { User author = Objects.requireNonNull(entry.getUser()); return getTargetFromEntryOrNull(entry).map(target -> new AuditLogMessage(author, action, @@ -99,7 +97,6 @@ private static boolean isSnowflakeAfter(ISnowflake snowflake, Instant timestamp) * @param periodHours the scheduling period in hours * @return the according schedule representing the planned execution */ - @Nonnull private static Schedule scheduleAtFixedRateFromNextFixedTime(int periodStartHour, int periodHours) { // NOTE This scheduler could be improved, for example supporting arbitrary periods (not just @@ -129,7 +126,6 @@ private static Schedule scheduleAtFixedRateFromNextFixedTime(int periodStartHour TimeUnit.HOURS.toSeconds(periodHours), TimeUnit.SECONDS); } - @Nonnull private static Instant computeClosestNextScheduleDate(Instant instant, List scheduleHours, int periodHours) { OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.UTC); @@ -151,36 +147,30 @@ private static Instant computeClosestNextScheduleDate(Instant instant, .orElseThrow(); } - @Nonnull private static Optional> handleBanEntry(AuditLogEntry entry) { // NOTE Temporary bans are realized as permanent bans with automated unban, // hence we can not differentiate a permanent or a temporary ban here return Optional.of(handleAction(Action.BAN, entry).map(AuditLogMessage::toEmbed)); } - @Nonnull private static Optional> handleUnbanEntry(AuditLogEntry entry) { return Optional.of(handleAction(Action.UNBAN, entry).map(AuditLogMessage::toEmbed)); } - @Nonnull private static Optional> handleKickEntry(AuditLogEntry entry) { return Optional.of(handleAction(Action.KICK, entry).map(AuditLogMessage::toEmbed)); } - @Nonnull private static Optional> handleMuteEntry(AuditLogEntry entry) { // NOTE Temporary mutes are realized as permanent mutes with automated unmute, // hence we can not differentiate a permanent or a temporary mute here return Optional.of(handleAction(Action.MUTE, entry).map(AuditLogMessage::toEmbed)); } - @Nonnull private static Optional> handleUnmuteEntry(AuditLogEntry entry) { return Optional.of(handleAction(Action.UNMUTE, entry).map(AuditLogMessage::toEmbed)); } - @Nonnull private static Optional> handleMessageDeleteEntry( AuditLogEntry entry) { return Optional.of(handleAction(Action.MESSAGE_DELETION, entry).map(message -> { @@ -198,7 +188,6 @@ public void runRoutine(JDA jda) { } @Override - @Nonnull public Schedule createSchedule() { Schedule schedule = scheduleAtFixedRateFromNextFixedTime(CHECK_AUDIT_LOG_START_HOUR, CHECK_AUDIT_LOG_EVERY_HOURS); @@ -270,7 +259,6 @@ private void handleAuditLogs(MessageChannel auditLogChannel, }); } - @Nonnull private Optional> handleAuditLog(MessageChannel auditLogChannel, AuditLogEntry entry) { Optional> maybeMessage = switch (entry.getType()) { @@ -290,7 +278,6 @@ private Optional> handleAuditLog(MessageChannel auditLogChan .map(message -> message.flatMap(Objects::nonNull, auditLogChannel::sendMessageEmbeds)); } - @Nonnull private Optional> handleRoleUpdateEntry(AuditLogEntry entry) { if (containsMutedRole(entry, AuditLogKey.MEMBER_ROLES_ADD)) { return handleMuteEntry(entry); @@ -329,12 +316,10 @@ private enum Action { this.verb = verb; } - @Nonnull String getTitle() { return title; } - @Nonnull String getVerb() { return verb; } @@ -342,7 +327,6 @@ String getVerb() { private record AuditLogMessage(User author, Action action, @Nullable User target, @Nullable String reason, TemporalAccessor timestamp) { - @Nonnull MessageEmbed toEmbed() { String targetTag = target == null ? "(user unknown)" : target.getAsTag(); String description = "%s **%s**.".formatted(action.getVerb(), targetTag); diff --git a/application/src/main/java/org/togetherjava/tjbot/routines/package-info.java b/application/src/main/java/org/togetherjava/tjbot/routines/package-info.java index 1d457b05f3..f3f1ca00cd 100644 --- a/application/src/main/java/org/togetherjava/tjbot/routines/package-info.java +++ b/application/src/main/java/org/togetherjava/tjbot/routines/package-info.java @@ -5,7 +5,10 @@ * Routines are actions that are executed periodically on a schedule. They are added to the system * in {@link org.togetherjava.tjbot.commands.Features}. */ +@MethodsReturnNonnullByDefault @ParametersAreNonnullByDefault package org.togetherjava.tjbot.routines; +import org.togetherjava.tjbot.annotations.MethodsReturnNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/basic/PingCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/basic/PingCommandTest.java index 38ac79caad..495995a8e7 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/basic/PingCommandTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/basic/PingCommandTest.java @@ -7,15 +7,12 @@ import org.togetherjava.tjbot.commands.SlashCommand; import org.togetherjava.tjbot.jda.JdaTester; -import javax.annotation.Nonnull; - import static org.mockito.Mockito.verify; final class PingCommandTest { private JdaTester jdaTester; private SlashCommand command; - @Nonnull private SlashCommandInteractionEvent triggerSlashCommand() { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(command).build(); diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommandTest.java index ee3fd8a431..1f518eb13b 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommandTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/mathcommands/TeXCommandTest.java @@ -8,7 +8,6 @@ import org.togetherjava.tjbot.commands.SlashCommand; import org.togetherjava.tjbot.jda.JdaTester; -import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; @@ -26,7 +25,6 @@ void setUp() { command = jdaTester.spySlashCommand(new TeXCommand()); } - @Nonnull private SlashCommandInteractionEvent triggerSlashCommand(String latex) { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(command) .setOption(TeXCommand.LATEX_OPTION, latex) diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/mediaonly/MediaOnlyChannelListenerTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/mediaonly/MediaOnlyChannelListenerTest.java index 894273d990..653d776970 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/mediaonly/MediaOnlyChannelListenerTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/mediaonly/MediaOnlyChannelListenerTest.java @@ -10,7 +10,6 @@ import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.jda.JdaTester; -import javax.annotation.Nonnull; import java.util.List; import static org.mockito.Mockito.*; @@ -94,12 +93,10 @@ void sendsAuthorDmUponDeletion() { verify(jdaTester.getPrivateChannelSpy()).sendMessage(any(Message.class)); } - @Nonnull private MessageReceivedEvent sendMessage(Message message) { return sendMessage(message, List.of()); } - @Nonnull private MessageReceivedEvent sendMessage(Message message, List attachments) { MessageReceivedEvent event = jdaTester.createMessageReceiveEvent(message, attachments); diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/moderation/scam/ScamDetectorTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/moderation/scam/ScamDetectorTest.java index 57210ba9d3..b2de1d67a0 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/moderation/scam/ScamDetectorTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/moderation/scam/ScamDetectorTest.java @@ -8,7 +8,6 @@ import org.togetherjava.tjbot.config.Config; import org.togetherjava.tjbot.config.ScamBlockerConfig; -import javax.annotation.Nonnull; import java.util.List; import java.util.Set; @@ -103,7 +102,6 @@ void websitesWithTooManyDifferencesAreNotSuspicious() { assertFalse(isScamResult); } - @Nonnull private static List provideRealScamMessages() { return List.of(""" 🀩bro steam gived nitro - https://nitro-ds.online/LfgUfMzqYyx12""", diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RawReminderTestHelper.java b/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RawReminderTestHelper.java index eab488d60f..2f676d7d16 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RawReminderTestHelper.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RawReminderTestHelper.java @@ -7,7 +7,6 @@ import org.togetherjava.tjbot.db.generated.tables.records.PendingRemindersRecord; import org.togetherjava.tjbot.jda.JdaTester; -import javax.annotation.Nonnull; import java.time.Instant; import java.util.List; @@ -45,12 +44,10 @@ void insertReminder(String content, Instant remindAt, Member author, TextChannel .insert()); } - @Nonnull List readReminders() { return readReminders(jdaTester.getMemberSpy()); } - @Nonnull List readReminders(Member author) { long guildId = jdaTester.getTextChannelSpy().getGuild().getIdLong(); long authorId = author.getIdLong(); diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RemindCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RemindCommandTest.java index d7e4b6d66d..857b98a278 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RemindCommandTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RemindCommandTest.java @@ -11,7 +11,6 @@ import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.jda.JdaTester; -import javax.annotation.Nonnull; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.List; @@ -35,13 +34,11 @@ void setUp() { rawReminders = new RawReminderTestHelper(database, jdaTester); } - @Nonnull private SlashCommandInteractionEvent triggerSlashCommand(int timeAmount, String timeUnit, String content) { return triggerSlashCommand(timeAmount, timeUnit, content, jdaTester.getMemberSpy()); } - @Nonnull private SlashCommandInteractionEvent triggerSlashCommand(int timeAmount, String timeUnit, String content, Member author) { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(command) diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RemindRoutineTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RemindRoutineTest.java index 1a65290bee..69aaaed1fb 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RemindRoutineTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/reminder/RemindRoutineTest.java @@ -12,7 +12,6 @@ import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.jda.JdaTester; -import javax.annotation.Nonnull; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.concurrent.TimeUnit; @@ -39,14 +38,12 @@ private void triggerRoutine() { routine.runRoutine(jdaTester.getJdaMock()); } - @Nonnull private static MessageEmbed getLastMessageFrom(MessageChannel channel) { ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(MessageEmbed.class); verify(channel).sendMessageEmbeds(responseCaptor.capture()); return responseCaptor.getValue(); } - @Nonnull private Member createAndSetupUnknownMember() { int unknownMemberId = 2; @@ -67,7 +64,6 @@ private Member createAndSetupUnknownMember() { return member; } - @Nonnull private TextChannel createAndSetupUnknownChannel() { long unknownChannelId = 2; diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/system/ReloadCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/system/ReloadCommandTest.java index d3be1e198f..69ca4c9518 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/system/ReloadCommandTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/system/ReloadCommandTest.java @@ -3,7 +3,6 @@ import org.junit.jupiter.api.Test; import org.togetherjava.tjbot.commands.SlashCommand; -import javax.annotation.Nonnull; import java.util.Collection; import java.util.List; import java.util.Optional; @@ -17,13 +16,11 @@ void ReloadCommand() { "AnonymousInnerClassMayBeStatic"}) SlashCommandProvider slashCommandProvider = new SlashCommandProvider() { @Override - @Nonnull public Collection getSlashCommands() { return List.of(); } @Override - @Nonnull public Optional getSlashCommand(String name) { return Optional.empty(); } diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java index 48d0733151..eced581e77 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagCommandTest.java @@ -12,7 +12,6 @@ import org.togetherjava.tjbot.jda.JdaTester; import org.togetherjava.tjbot.jda.SlashCommandInteractionEventBuilder; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import static org.mockito.Mockito.*; @@ -30,7 +29,6 @@ void setUp() { command = new TagCommand(system); } - @Nonnull private SlashCommandInteractionEvent triggerSlashCommand(String id, @Nullable Member userToReplyTo) { SlashCommandInteractionEventBuilder builder = diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagManageCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagManageCommandTest.java index 94776f6029..f2b388aa63 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagManageCommandTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagManageCommandTest.java @@ -19,7 +19,6 @@ import org.togetherjava.tjbot.jda.JdaTester; import org.togetherjava.tjbot.moderation.ModAuditLogWriter; -import javax.annotation.Nonnull; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; @@ -36,7 +35,6 @@ final class TagManageCommandTest { private Member moderator; private ModAuditLogWriter modAuditLogWriter; - @Nonnull private static MessageEmbed getResponse(SlashCommandInteractionEvent event) { ArgumentCaptor responseCaptor = ArgumentCaptor.forClass(MessageEmbed.class); verify(event).replyEmbeds(responseCaptor.capture()); @@ -62,12 +60,10 @@ void setUp() { when(moderatorRole.getName()).thenReturn(moderatorRoleName); } - @Nonnull private SlashCommandInteractionEvent triggerRawCommand(String tagId) { return triggerRawCommandWithUser(tagId, moderator); } - @Nonnull private SlashCommandInteractionEvent triggerRawCommandWithUser(String tagId, Member user) { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(command) .setSubcommand(TagManageCommand.Subcommand.RAW.getName()) @@ -79,17 +75,14 @@ private SlashCommandInteractionEvent triggerRawCommandWithUser(String tagId, Mem return event; } - @Nonnull private SlashCommandInteractionEvent triggerCreateCommand(String tagId, String content) { return triggerTagContentCommand(TagManageCommand.Subcommand.CREATE, tagId, content); } - @Nonnull private SlashCommandInteractionEvent triggerEditCommand(String tagId, String content) { return triggerTagContentCommand(TagManageCommand.Subcommand.EDIT, tagId, content); } - @Nonnull private SlashCommandInteractionEvent triggerTagContentCommand( TagManageCommand.Subcommand subcommand, String tagId, String content) { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(command) @@ -103,21 +96,18 @@ private SlashCommandInteractionEvent triggerTagContentCommand( return event; } - @Nonnull private SlashCommandInteractionEvent triggerCreateWithMessageCommand(String tagId, String messageId) { return triggerTagMessageCommand(TagManageCommand.Subcommand.CREATE_WITH_MESSAGE, tagId, messageId); } - @Nonnull private SlashCommandInteractionEvent triggerEditWithMessageCommand(String tagId, String messageId) { return triggerTagMessageCommand(TagManageCommand.Subcommand.EDIT_WITH_MESSAGE, tagId, messageId); } - @Nonnull private SlashCommandInteractionEvent triggerTagMessageCommand( TagManageCommand.Subcommand subcommand, String tagId, String messageId) { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(command) @@ -131,7 +121,6 @@ private SlashCommandInteractionEvent triggerTagMessageCommand( return event; } - @Nonnull private SlashCommandInteractionEvent triggerDeleteCommand(String tagId) { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(command) .setSubcommand(TagManageCommand.Subcommand.DELETE.getName()) diff --git a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagsCommandTest.java b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagsCommandTest.java index 33e56f028d..870931ca49 100644 --- a/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagsCommandTest.java +++ b/application/src/test/java/org/togetherjava/tjbot/commands/tags/TagsCommandTest.java @@ -15,7 +15,6 @@ import org.togetherjava.tjbot.db.generated.tables.Tags; import org.togetherjava.tjbot.jda.JdaTester; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; @@ -35,7 +34,6 @@ private static String getResponseDescription(SlashCommandInteractionEvent event) return responseCaptor.getValue().getDescription(); } - @Nonnull private SlashCommandInteractionEvent triggerSlashCommand() { SlashCommandInteractionEvent event = jdaTester.createSlashCommandInteractionEvent(command).build(); @@ -43,7 +41,6 @@ private SlashCommandInteractionEvent triggerSlashCommand() { return event; } - @Nonnull private ButtonInteractionEvent triggerButtonClick(Member userWhoClicked, long idOfAuthor) { ButtonInteractionEvent event = jdaTester.createButtonInteractionEvent() .setUserWhoClicked(userWhoClicked) diff --git a/application/src/test/java/org/togetherjava/tjbot/jda/ButtonClickEventBuilder.java b/application/src/test/java/org/togetherjava/tjbot/jda/ButtonClickEventBuilder.java index 115fd86531..f336c0d5bc 100644 --- a/application/src/test/java/org/togetherjava/tjbot/jda/ButtonClickEventBuilder.java +++ b/application/src/test/java/org/togetherjava/tjbot/jda/ButtonClickEventBuilder.java @@ -11,7 +11,6 @@ import net.dv8tion.jda.api.interactions.components.buttons.Button; import org.togetherjava.tjbot.commands.SlashCommand; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; import java.util.function.Function; @@ -94,7 +93,6 @@ public final class ButtonClickEventBuilder { * @param message the message to set * @return this builder instance for chaining */ - @Nonnull public ButtonClickEventBuilder setMessage(Message message) { messageBuilder = new MessageBuilder(message); return this; @@ -107,7 +105,6 @@ public ButtonClickEventBuilder setMessage(Message message) { * @param content the content of the message * @return this builder instance for chaining */ - @Nonnull public ButtonClickEventBuilder setContent(String content) { messageBuilder.setContent(content); return this; @@ -120,7 +117,6 @@ public ButtonClickEventBuilder setContent(String content) { * @param embeds the embeds of the message * @return this builder instance for chaining */ - @Nonnull public ButtonClickEventBuilder setEmbeds(MessageEmbed... embeds) { messageBuilder.setEmbeds(embeds); return this; @@ -135,7 +131,6 @@ public ButtonClickEventBuilder setEmbeds(MessageEmbed... embeds) { * @param rows the action rows of the message * @return this builder instance for chaining */ - @Nonnull public ButtonClickEventBuilder setActionRows(ActionRow... rows) { messageBuilder.setActionRows(rows); return this; @@ -147,7 +142,6 @@ public ButtonClickEventBuilder setActionRows(ActionRow... rows) { * @param userWhoClicked the user who clicked the button * @return this builder instance for chaining */ - @Nonnull public ButtonClickEventBuilder setUserWhoClicked(Member userWhoClicked) { this.userWhoClicked = userWhoClicked; return this; @@ -162,7 +156,6 @@ public ButtonClickEventBuilder setUserWhoClicked(Member userWhoClicked) { * * @return the created slash command instance */ - @Nonnull public ButtonInteractionEvent buildWithSingleButton() { return createEvent(null); } @@ -178,12 +171,10 @@ public ButtonInteractionEvent buildWithSingleButton() { * contained in the message. * @return the created slash command instance */ - @Nonnull public ButtonInteractionEvent build(Button clickedButton) { return createEvent(clickedButton); } - @Nonnull private ButtonInteractionEvent createEvent(@Nullable Button maybeClickedButton) { Message message = mockMessageOperator.apply(messageBuilder.build()); Button clickedButton = determineClickedButton(maybeClickedButton, message); @@ -191,7 +182,6 @@ private ButtonInteractionEvent createEvent(@Nullable Button maybeClickedButton) return mockButtonClickEvent(message, clickedButton); } - @Nonnull private static Button determineClickedButton(@Nullable Button maybeClickedButton, Message message) { if (maybeClickedButton != null) { @@ -203,7 +193,6 @@ private static Button determineClickedButton(@Nullable Button maybeClickedButton return requireSingleButton(getMessageButtons(message)); } - @Nonnull private static Button requireButtonInMessage(Button clickedButton, Message message) { boolean isClickedButtonUnknown = getMessageButtons(message).noneMatch(clickedButton::equals); @@ -216,7 +205,6 @@ private static Button requireButtonInMessage(Button clickedButton, Message messa return clickedButton; } - @Nonnull private static Button requireSingleButton(Stream stream) { Function descriptionToException = IllegalArgumentException::new; @@ -231,12 +219,10 @@ private static Button requireSingleButton(Stream stream) { + " Add the button to the message first.")); } - @Nonnull private static Stream