From 59947b288ca0e70b2a48b45be17322e064ce60a0 Mon Sep 17 00:00:00 2001 From: Yannick Lamprecht Date: Sat, 14 Dec 2024 15:19:03 +0100 Subject: [PATCH] generate javadocs --- .../java/de/chojo/repbot/ReputationBot.java | 18 ++ .../actions/messages/log/MessageLog.java | 13 ++ .../messages/log/handler/MessageAnalyzer.java | 14 ++ .../user/donated/received/UserDonated.java | 16 ++ .../received/handler/DonatedReputation.java | 16 +- .../actions/user/received/UserReceived.java | 16 ++ .../received/handler/ReceivedReputation.java | 15 +- .../repbot/analyzer/ContextResolver.java | 88 +++++++-- .../repbot/analyzer/MessageAnalyzer.java | 56 +++++- .../chojo/repbot/analyzer/MessageContext.java | 114 ++++++++++- .../analyzer/results/AnalyzerResult.java | 68 +++++++ .../repbot/analyzer/results/ResultType.java | 10 + .../results/empty/EmptyAnalyzerResult.java | 23 +++ .../results/empty/EmptyResultReason.java | 36 ++++ .../results/match/AnswerAnalyzerResult.java | 34 ++++ .../results/match/DirectAnalyzerResult.java | 26 +++ .../results/match/FuzzyAnalyzerResult.java | 39 +++- .../results/match/MatchAnalyzerResult.java | 55 ++++++ .../analyzer/results/match/ThankType.java | 36 ++++ .../results/match/fuzzy/MemberMatch.java | 36 ++++ .../abuseprotection/AbuseProtection.java | 11 +- .../abuseprotection/handler/Info.java | 21 ++ .../handler/context/DonorContext.java | 15 +- .../handler/context/ReceiverContext.java | 14 ++ .../handler/limit/Cooldown.java | 15 +- .../handler/limit/DonorLimit.java | 14 ++ .../handler/limit/ReceiverLimit.java | 14 ++ .../handler/message/MaxMessageAge.java | 14 ++ .../handler/message/MaxMessageReputation.java | 14 ++ .../handler/message/MinMessages.java | 14 ++ .../chojo/repbot/commands/bot/BotAdmin.java | 10 + .../repbot/commands/bot/handler/Debug.java | 26 +++ .../commands/bot/handler/InvalidateCache.java | 14 ++ .../repbot/commands/bot/handler/Leave.java | 16 ++ .../repbot/commands/bot/handler/Redeploy.java | 17 +- .../repbot/commands/bot/handler/Search.java | 15 ++ .../commands/bot/handler/SharedGuilds.java | 15 ++ .../commands/bot/handler/log/Analyzer.java | 14 ++ .../commands/bot/handler/system/Metrics.java | 20 ++ .../commands/bot/handler/system/Reload.java | 14 ++ .../commands/bot/handler/system/Restart.java | 14 ++ .../commands/bot/handler/system/Shudown.java | 15 ++ .../commands/bot/handler/system/Status.java | 14 ++ .../commands/bot/handler/system/Upgrade.java | 21 ++ .../repbot/commands/channel/Channel.java | 8 + .../repbot/commands/channel/handler/Add.java | 26 ++- .../channel/handler/BaseChannelModifier.java | 30 +++ .../repbot/commands/channel/handler/List.java | 21 ++ .../commands/channel/handler/ListType.java | 20 ++ .../commands/channel/handler/Remove.java | 25 +++ .../repbot/commands/channel/handler/Set.java | 25 +++ .../channel/handler/announcement/Info.java | 14 ++ .../handler/announcement/Location.java | 14 ++ .../channel/handler/announcement/State.java | 15 ++ .../channel/handler/announcement/Where.java | 20 ++ .../repbot/commands/dashboard/Dashboard.java | 8 + .../commands/dashboard/handler/Show.java | 22 +++ .../de/chojo/repbot/commands/debug/Debug.java | 8 + .../repbot/commands/debug/handler/Show.java | 14 ++ .../de/chojo/repbot/commands/gdpr/Gdpr.java | 8 + .../repbot/commands/gdpr/handler/Delete.java | 14 ++ .../repbot/commands/gdpr/handler/Request.java | 14 ++ .../de/chojo/repbot/commands/info/Info.java | 15 ++ .../repbot/commands/info/handler/Show.java | 60 ++++++ .../chojo/repbot/commands/invite/Invite.java | 9 + .../repbot/commands/invite/handler/Show.java | 21 ++ .../chojo/repbot/commands/locale/Locale.java | 8 + .../repbot/commands/locale/handler/List.java | 16 ++ .../repbot/commands/locale/handler/Reset.java | 14 ++ .../repbot/commands/locale/handler/Set.java | 20 ++ .../de/chojo/repbot/commands/log/Log.java | 8 + .../repbot/commands/log/handler/Analyzer.java | 24 ++- .../commands/log/handler/BaseAnalyzer.java | 18 +- .../repbot/commands/log/handler/Donated.java | 23 ++- .../commands/log/handler/LogFormatter.java | 44 +++++ .../repbot/commands/log/handler/Message.java | 22 +++ .../repbot/commands/log/handler/Received.java | 24 ++- .../repbot/commands/messages/Messages.java | 8 + .../commands/messages/handler/States.java | 40 ++++ .../de/chojo/repbot/commands/prune/Prune.java | 8 + .../repbot/commands/prune/handler/Guild.java | 14 ++ .../repbot/commands/prune/handler/User.java | 17 ++ .../repbot/commands/reactions/Reactions.java | 8 + .../commands/reactions/handler/Add.java | 22 +++ .../commands/reactions/handler/Info.java | 22 ++- .../commands/reactions/handler/Main.java | 22 +++ .../commands/reactions/handler/Remove.java | 20 ++ .../commands/reactions/util/CheckResult.java | 23 ++- .../commands/reactions/util/EmojiCheck.java | 24 ++- .../reactions/util/EmojiCheckResult.java | 7 + .../repbot/commands/repadmin/RepAdmin.java | 10 + .../commands/repadmin/handler/Profile.java | 15 ++ .../repadmin/handler/reputation/Add.java | 18 ++ .../reputation/BaseReputationModifier.java | 24 +++ .../repadmin/handler/reputation/Remove.java | 18 ++ .../repadmin/handler/reputation/Set.java | 21 ++ .../handler/resetdate/CurrentResetDate.java | 14 ++ .../handler/resetdate/RemoveResetDate.java | 14 ++ .../handler/resetdate/SetResetDate.java | 15 ++ .../commands/repsettings/RepSettings.java | 8 + .../repsettings/handler/EmojiInfo.java | 26 +++ .../commands/repsettings/handler/Info.java | 39 ++++ .../commands/reputation/Reputation.java | 10 + .../commands/reputation/handler/Profile.java | 16 ++ .../de/chojo/repbot/commands/roles/Roles.java | 22 ++- .../repbot/commands/roles/handler/Add.java | 16 ++ .../roles/handler/BaseRoleModifier.java | 27 +++ .../repbot/commands/roles/handler/List.java | 21 ++ .../commands/roles/handler/Refresh.java | 27 +++ .../repbot/commands/roles/handler/Remove.java | 16 ++ .../commands/roles/handler/StackRoles.java | 17 ++ .../roles/handler/donor/AddDonor.java | 14 ++ .../roles/handler/donor/RemoveDonor.java | 14 ++ .../roles/handler/receiver/AddReceiver.java | 14 ++ .../handler/receiver/RemoveReceiver.java | 14 ++ .../de/chojo/repbot/commands/scan/Scan.java | 25 +++ .../repbot/commands/scan/handler/Cancel.java | 14 ++ .../repbot/commands/scan/handler/Start.java | 15 ++ .../commands/scan/util/ScanProcess.java | 75 ++++++- .../repbot/commands/scan/util/Scanner.java | 98 +++++++++ .../de/chojo/repbot/commands/setup/Setup.java | 17 ++ .../repbot/commands/setup/handler/Start.java | 87 ++++++++ .../commands/thankwords/Thankwords.java | 26 +++ .../commands/thankwords/handler/Add.java | 14 ++ .../commands/thankwords/handler/Check.java | 21 ++ .../commands/thankwords/handler/List.java | 20 ++ .../thankwords/handler/LoadDefault.java | 21 ++ .../commands/thankwords/handler/Remove.java | 20 ++ .../de/chojo/repbot/commands/top/Top.java | 9 + .../repbot/commands/top/handler/Show.java | 37 +++- .../de/chojo/repbot/config/ConfigFile.java | 64 ++++++ .../de/chojo/repbot/config/Configuration.java | 89 +++++++++ .../config/elements/AnalyzerSettings.java | 29 +++ .../de/chojo/repbot/config/elements/Api.java | 26 ++- .../chojo/repbot/config/elements/Badges.java | 9 + .../repbot/config/elements/BaseSettings.java | 25 +++ .../chojo/repbot/config/elements/Botlist.java | 64 ++++++ .../chojo/repbot/config/elements/Cleanup.java | 39 +++- .../repbot/config/elements/Database.java | 72 ++++++- .../chojo/repbot/config/elements/Links.java | 34 ++++ .../repbot/config/elements/MagicImage.java | 45 ++++- .../config/elements/PresenceSettings.java | 56 ++++++ .../repbot/config/elements/SelfCleanup.java | 60 ++++++ .../exception/ConfigurationException.java | 3 + src/main/java/de/chojo/repbot/core/Bot.java | 51 +++++ src/main/java/de/chojo/repbot/core/Data.java | 77 ++++++++ .../de/chojo/repbot/core/Localization.java | 22 +++ .../java/de/chojo/repbot/core/Shutdown.java | 24 ++- .../java/de/chojo/repbot/core/Threading.java | 79 ++++++++ src/main/java/de/chojo/repbot/core/Web.java | 32 +++ .../de/chojo/repbot/dao/access/Analyzer.java | 11 ++ .../de/chojo/repbot/dao/access/Cleanup.java | 15 ++ .../java/de/chojo/repbot/dao/access/Gdpr.java | 33 +++- .../repbot/dao/access/gdpr/GdprUser.java | 42 ++++ .../repbot/dao/access/gdpr/RemovalTask.java | 41 ++++ .../repbot/dao/access/guild/Cleanup.java | 29 +++ .../chojo/repbot/dao/access/guild/Gdpr.java | 24 +++ .../repbot/dao/access/guild/RepGuild.java | 102 ++++++++-- .../repbot/dao/access/guild/RepGuildId.java | 14 ++ .../access/guild/reputation/Reputation.java | 63 +++++- .../access/guild/reputation/sub/Analyzer.java | 54 ++++- .../dao/access/guild/reputation/sub/Log.java | 97 +++++++-- .../access/guild/reputation/sub/Ranking.java | 120 ++++++++++- .../access/guild/reputation/sub/RepUser.java | 121 ++++++++---- .../guild/reputation/sub/user/Gdpr.java | 29 +++ .../dao/access/guild/settings/Settings.java | 59 ++++++ .../guild/settings/sub/AbuseProtection.java | 187 +++++++++++++++++- .../guild/settings/sub/Announcements.java | 81 +++++++- .../access/guild/settings/sub/General.java | 108 ++++++++++ .../access/guild/settings/sub/Messages.java | 67 +++++++ .../dao/access/guild/settings/sub/Ranks.java | 62 +++++- .../access/guild/settings/sub/Reputation.java | 134 +++++++++++++ .../guild/settings/sub/ReputationMode.java | 60 ++++++ .../access/guild/settings/sub/Thanking.java | 63 +++++- .../guild/settings/sub/thanking/Channels.java | 91 +++++++-- .../settings/sub/thanking/DonorRoles.java | 24 +++ .../settings/sub/thanking/Reactions.java | 77 +++++++- .../settings/sub/thanking/ReceiverRoles.java | 24 +++ .../settings/sub/thanking/RolesHolder.java | 56 ++++++ .../settings/sub/thanking/Thankwords.java | 59 +++++- .../repbot/dao/access/metrics/Commands.java | 61 +++++- .../repbot/dao/access/metrics/Messages.java | 67 +++++++ .../repbot/dao/access/metrics/Reputation.java | 137 ++++++++++++- .../repbot/dao/access/metrics/Service.java | 59 +++++- .../repbot/dao/access/metrics/Statistic.java | 32 ++- .../repbot/dao/access/metrics/Users.java | 37 +++- .../repbot/dao/components/GuildHolder.java | 14 ++ .../repbot/dao/components/MemberHolder.java | 28 +++ .../repbot/dao/components/UserHolder.java | 13 ++ .../repbot/dao/pagination/GuildList.java | 10 + .../repbot/dao/pagination/GuildRanking.java | 15 ++ .../repbot/dao/pagination/PageAccess.java | 36 +++- .../dao/pagination/ReputationLogAccess.java | 10 + .../de/chojo/repbot/dao/provider/Guilds.java | 46 ++++- .../de/chojo/repbot/dao/provider/Metrics.java | 38 ++++ .../de/chojo/repbot/dao/provider/Voice.java | 32 ++- .../repbot/dao/snapshots/AnalyzerTrace.java | 14 ++ .../dao/snapshots/GuildReputationStats.java | 8 + .../repbot/dao/snapshots/RepProfile.java | 67 ++++++- .../dao/snapshots/ReputationLogEntry.java | 91 ++++++++- .../repbot/dao/snapshots/ReputationRank.java | 63 +++++- .../repbot/dao/snapshots/ResultEntry.java | 15 ++ .../dao/snapshots/SubmitResultEntry.java | 8 + .../snapshots/analyzer/ResultSnapshot.java | 11 ++ .../analyzer/match/AnswerResultSnapshot.java | 18 ++ .../analyzer/match/DirectResultSnapshot.java | 23 +++ .../analyzer/match/FuzzyResultSnapshot.java | 18 ++ .../analyzer/match/MatchResultSnapshot.java | 32 +++ .../snapshots/statistics/ChartProvider.java | 9 + .../statistics/CommandStatistic.java | 16 +- .../statistics/CommandsStatistic.java | 12 ++ .../snapshots/statistics/CountStatistics.java | 32 ++- .../snapshots/statistics/CountsStatistic.java | 24 ++- .../snapshots/statistics/DowStatistics.java | 26 +++ .../snapshots/statistics/DowsStatistic.java | 16 ++ .../statistics/LabeledCountStatistic.java | 17 ++ .../snapshots/statistics/UserStatistic.java | 23 +++ .../snapshots/statistics/UsersStatistic.java | 18 +- .../builder/LabeledCountStatisticBuilder.java | 21 ++ .../de/chojo/repbot/listener/LogListener.java | 47 +++++ .../repbot/listener/MessageListener.java | 44 +++++ .../repbot/listener/ReactionListener.java | 43 +++- .../chojo/repbot/listener/StateListener.java | 63 ++++++ .../repbot/listener/VoiceStateListener.java | 23 +++ .../voting/ReputationVoteListener.java | 30 ++- .../repbot/listener/voting/VoteComponent.java | 7 +- .../repbot/listener/voting/VoteRequest.java | 73 +++++++ .../serialization/ThankwordsContainer.java | 19 ++ .../chojo/repbot/service/AnalyzerService.java | 18 +- .../de/chojo/repbot/service/GdprService.java | 39 +++- .../chojo/repbot/service/MetricService.java | 18 ++ .../chojo/repbot/service/PresenceService.java | 24 +++ .../repbot/service/RepBotCachePolicy.java | 35 +++- .../repbot/service/RoleAccessException.java | 13 ++ .../de/chojo/repbot/service/RoleAssigner.java | 49 ++++- .../de/chojo/repbot/service/RoleUpdater.java | 44 +++++ .../repbot/service/SelfCleanupService.java | 50 ++++- .../service/reputation/ReputationService.java | 83 +++++++- .../service/reputation/SubmitResult.java | 20 ++ .../service/reputation/SubmitResultType.java | 84 ++++++++ .../chojo/repbot/statistic/EmbedDisplay.java | 8 + .../repbot/statistic/ReplacementProvider.java | 8 + .../de/chojo/repbot/statistic/Statistic.java | 31 +++ .../display/GlobalInfoStatisticDisplay.java | 12 +- .../display/SystemInfoStatisticDisplay.java | 11 ++ .../statistic/element/DataStatistic.java | 63 ++++++ .../element/GlobalShardStatistic.java | 19 +- .../statistic/element/ProcessStatistics.java | 29 +++ .../element/ShardCountStatistic.java | 20 ++ .../statistic/element/ShardStatistic.java | 13 ++ .../statistic/element/SystemStatistics.java | 40 ++++ .../java/de/chojo/repbot/util/Colors.java | 96 +++++++++ .../java/de/chojo/repbot/util/EmojiDebug.java | 42 ++++ .../java/de/chojo/repbot/util/FilterUtil.java | 20 +- .../java/de/chojo/repbot/util/Guilds.java | 14 ++ .../java/de/chojo/repbot/util/LogNotify.java | 20 +- .../java/de/chojo/repbot/util/Messages.java | 30 +++ .../repbot/util/PermissionErrorHandler.java | 42 ++++ src/main/java/de/chojo/repbot/util/Roles.java | 13 ++ src/main/java/de/chojo/repbot/util/Text.java | 103 ++++++++++ src/main/java/de/chojo/repbot/web/Api.java | 14 +- .../chojo/repbot/web/error/ApiException.java | 19 +- .../repbot/web/routes/RoutesBuilder.java | 6 + .../repbot/web/routes/v1/MetricsHolder.java | 52 ++++- .../repbot/web/routes/v1/MetricsRoute.java | 112 ++++++++++- .../web/routes/v1/metrics/Commands.java | 36 +++- .../web/routes/v1/metrics/Messages.java | 47 +++++ .../web/routes/v1/metrics/MetricCache.java | 36 ++++ .../web/routes/v1/metrics/Reputation.java | 78 +++++++- .../repbot/web/routes/v1/metrics/Service.java | 32 +++ .../repbot/web/routes/v1/metrics/Users.java | 22 +++ 271 files changed, 8635 insertions(+), 259 deletions(-) diff --git a/src/main/java/de/chojo/repbot/ReputationBot.java b/src/main/java/de/chojo/repbot/ReputationBot.java index a6f79a2c3..feca750e6 100644 --- a/src/main/java/de/chojo/repbot/ReputationBot.java +++ b/src/main/java/de/chojo/repbot/ReputationBot.java @@ -17,9 +17,26 @@ import java.io.IOException; import java.sql.SQLException; +/** + * Main class for the ReputationBot application. + */ public class ReputationBot { private static ReputationBot instance; + /** + * Creates a new ReputationBot instance. + */ + private ReputationBot() { + } + + /** + * Main method to start the ReputationBot application. + * + * @param args the command line arguments + * @throws SQLException If the database connection fails. + * @throws IOException If the configuration file fails to load. + * @throws LoginException If the bot login fails. + */ public static void main(String[] args) throws SQLException, IOException, LoginException { ReputationBot.instance = new ReputationBot(); instance.start(); @@ -30,6 +47,7 @@ public static void main(String[] args) throws SQLException, IOException, LoginEx * * @throws SQLException If the database connection fails. * @throws IOException If the configuration file fails to load. + * @throws LoginException If the bot login fails. */ private void start() throws SQLException, IOException, LoginException { var configuration = Configuration.create(); diff --git a/src/main/java/de/chojo/repbot/actions/messages/log/MessageLog.java b/src/main/java/de/chojo/repbot/actions/messages/log/MessageLog.java index 47929b21e..8c0f085ec 100644 --- a/src/main/java/de/chojo/repbot/actions/messages/log/MessageLog.java +++ b/src/main/java/de/chojo/repbot/actions/messages/log/MessageLog.java @@ -11,13 +11,26 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.Permission; +/** + * Provides a message log functionality for the bot. + */ public class MessageLog implements MessageProvider { private final Guilds guilds; + /** + * Constructs a MessageLog with the specified guilds provider. + * + * @param guilds the guilds provider + */ public MessageLog(Guilds guilds) { this.guilds = guilds; } + /** + * Returns a configured message for logging. + * + * @return the configured message + */ @Override public Message message() { return Message.of("Message Log") diff --git a/src/main/java/de/chojo/repbot/actions/messages/log/handler/MessageAnalyzer.java b/src/main/java/de/chojo/repbot/actions/messages/log/handler/MessageAnalyzer.java index 419c4685f..addb28370 100644 --- a/src/main/java/de/chojo/repbot/actions/messages/log/handler/MessageAnalyzer.java +++ b/src/main/java/de/chojo/repbot/actions/messages/log/handler/MessageAnalyzer.java @@ -11,13 +11,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent; +/** + * Handler for analyzing messages in the context of a guild. + */ public class MessageAnalyzer implements MessageHandler { private final Guilds guilds; + /** + * Constructs a new MessageAnalyzer handler. + * + * @param guilds the Guilds provider + */ public MessageAnalyzer(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the message context interaction event. + * + * @param event the MessageContextInteractionEvent + * @param eventContext the EventContext + */ @Override public void onMessage(MessageContextInteractionEvent event, EventContext eventContext) { Analyzer.sendAnalyzerLog(event, guilds, event.getTarget().getIdLong(), eventContext); diff --git a/src/main/java/de/chojo/repbot/actions/user/donated/received/UserDonated.java b/src/main/java/de/chojo/repbot/actions/user/donated/received/UserDonated.java index 2e9e61972..7036f5c78 100644 --- a/src/main/java/de/chojo/repbot/actions/user/donated/received/UserDonated.java +++ b/src/main/java/de/chojo/repbot/actions/user/donated/received/UserDonated.java @@ -11,13 +11,29 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.Permission; +/** + * Class for handling user donated actions. + */ public class UserDonated implements UserProvider { + /** + * Provider for accessing guild data. + */ private final Guilds guilds; + /** + * Constructs a new UserDonated instance. + * + * @param guilds the guilds provider + */ public UserDonated(Guilds guilds) { this.guilds = guilds; } + /** + * Creates and returns a User object configured for donated reputation. + * + * @return the configured User object + */ @Override public User user() { return User.of("Given Reputation").handler(new DonatedReputation(guilds)) diff --git a/src/main/java/de/chojo/repbot/actions/user/donated/received/handler/DonatedReputation.java b/src/main/java/de/chojo/repbot/actions/user/donated/received/handler/DonatedReputation.java index 834002bea..3e468ecc5 100644 --- a/src/main/java/de/chojo/repbot/actions/user/donated/received/handler/DonatedReputation.java +++ b/src/main/java/de/chojo/repbot/actions/user/donated/received/handler/DonatedReputation.java @@ -8,18 +8,30 @@ import de.chojo.jdautil.interactions.user.UserHandler; import de.chojo.jdautil.wrapper.EventContext; import de.chojo.repbot.commands.log.handler.Donated; -import de.chojo.repbot.commands.log.handler.Received; import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent; +/** + * Handles the donated reputation user context interaction. + */ public class DonatedReputation implements UserHandler { private final Guilds guilds; + /** + * Constructs a new DonatedReputation handler. + * + * @param guilds the Guilds provider + */ public DonatedReputation(Guilds guilds) { this.guilds = guilds; } - + /** + * Handles the user context interaction event. + * + * @param event the user context interaction event + * @param eventContext the event context + */ @Override public void onUser(UserContextInteractionEvent event, EventContext eventContext) { Donated.send(event, event.getTargetMember(), guilds, eventContext); diff --git a/src/main/java/de/chojo/repbot/actions/user/received/UserReceived.java b/src/main/java/de/chojo/repbot/actions/user/received/UserReceived.java index 22fe7ddf7..40e46adc6 100644 --- a/src/main/java/de/chojo/repbot/actions/user/received/UserReceived.java +++ b/src/main/java/de/chojo/repbot/actions/user/received/UserReceived.java @@ -11,13 +11,29 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.Permission; +/** + * Class for handling user received actions. + */ public class UserReceived implements UserProvider { + /** + * Provider for accessing guild data. + */ private final Guilds guilds; + /** + * Constructs a new UserReceived instance. + * + * @param guilds the guilds provider + */ public UserReceived(Guilds guilds) { this.guilds = guilds; } + /** + * Creates and returns a User object configured for received reputation. + * + * @return the configured User object + */ @Override public User user() { return User.of("Received Reputation").handler(new ReceivedReputation(guilds)) diff --git a/src/main/java/de/chojo/repbot/actions/user/received/handler/ReceivedReputation.java b/src/main/java/de/chojo/repbot/actions/user/received/handler/ReceivedReputation.java index a3c9daea0..9c8a00b23 100644 --- a/src/main/java/de/chojo/repbot/actions/user/received/handler/ReceivedReputation.java +++ b/src/main/java/de/chojo/repbot/actions/user/received/handler/ReceivedReputation.java @@ -11,14 +11,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent; +/** + * Handles the received reputation user context interaction. + */ public class ReceivedReputation implements UserHandler { private final Guilds guilds; + /** + * Constructs a ReceivedReputation handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public ReceivedReputation(Guilds guilds) { this.guilds = guilds; } - + /** + * Handles the user context interaction event. + * + * @param event the user context interaction event + * @param eventContext the event context + */ @Override public void onUser(UserContextInteractionEvent event, EventContext eventContext) { Received.send(event, event.getTargetMember(), guilds, eventContext); diff --git a/src/main/java/de/chojo/repbot/analyzer/ContextResolver.java b/src/main/java/de/chojo/repbot/analyzer/ContextResolver.java index d6bff3fac..eccee0355 100644 --- a/src/main/java/de/chojo/repbot/analyzer/ContextResolver.java +++ b/src/main/java/de/chojo/repbot/analyzer/ContextResolver.java @@ -31,6 +31,9 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Class responsible for resolving context for messages and voice states. + */ public class ContextResolver { private static final Logger log = getLogger(ContextResolver.class); private final Voice voiceData; @@ -46,6 +49,12 @@ public class ContextResolver { .expireAfterWrite(10, TimeUnit.SECONDS) .build(); + /** + * Constructs a ContextResolver instance with the specified voice data and configuration. + * + * @param voiceData the voice data provider + * @param configuration the configuration settings + */ public ContextResolver(Voice voiceData, Configuration configuration) { this.voiceData = voiceData; this.configuration = configuration; @@ -57,20 +66,29 @@ public ContextResolver(Voice voiceData, Configuration configuration) { * Only members which have written in the last 100 messages which are not older than the max history and are not * send before the first message of the message author are returned * - * @param message message to determine channel, author and start time - * @param settings setting sof the guild. - * @return list of members which have written in this channel + * @param target the target member + * @param message the message to determine channel, author, and start time + * @param settings the settings of the guild + * @return the message context */ @NotNull public MessageContext getChannelContext(Member target, Message message, @Nullable Settings settings) { try { return messageContextCache.get(message.getIdLong(), () -> retrieveChannelContext(target, message, settings).resolve()); } catch (ExecutionException e) { - log.error("Could not conpute channel context.", e); + log.error("Could not compute channel context.", e); } return MessageContext.byMessageAndMember(message, target); } + /** + * Retrieves the channel context for the specified message. + * + * @param target the target member + * @param message the message to determine channel, author, and start time + * @param settings the settings of the guild + * @return the message context + */ private MessageContext retrieveChannelContext(Member target, Message message, Settings settings) { var history = message.getChannel().getHistoryBefore(message, configuration.analyzerSettings().historySize()) .complete(); @@ -92,12 +110,12 @@ private MessageContext retrieveChannelContext(Member target, Message message, Se } /** - * Add the latest authors. + * Adds the latest authors to the context. *

- * Authors are considered latest when they have written a message in the last {@link AbuseProtection#minMessages()} + * Authors are considered latest when they have written a message in the last {@link AbuseProtection#minMessages()}. * - * @param context context to add - * @param settings settings + * @param context the message context + * @param settings the settings of the guild */ private void addLatestAuthors(MessageContext context, @Nullable Settings settings) { var maxAge = Instant.now().minus(configuration.analyzerSettings().latestMaxHours(), ChronoUnit.HOURS); @@ -111,12 +129,12 @@ private void addLatestAuthors(MessageContext context, @Nullable Settings setting } /** - * Add the recent authors. + * Adds the recent authors to the context. *

- * Authors are considered recent when they have written a message in the {@link AbuseProtection#maxMessageAge()} + * Authors are considered recent when they have written a message in the {@link AbuseProtection#maxMessageAge()}. * - * @param context context to add - * @param settings settings + * @param context the message context + * @param settings the settings of the guild */ private void addRecentAuthors(MessageContext context, Settings settings) { var maxAge = Instant.now().minus(settings == null ? Long.MAX_VALUE : settings.abuseProtection() @@ -128,11 +146,11 @@ private void addRecentAuthors(MessageContext context, Settings settings) { } /** - * Add the ids and messages which were newer than oldest to the context + * Adds the IDs and messages which were newer than the oldest to the context. * - * @param messages messages - * @param context context - * @param oldest oldest allowed message + * @param messages the messages + * @param context the message context + * @param oldest the oldest allowed message */ private void addMembersAfter(Collection messages, MessageContext context, Instant oldest) { // filter message for only recent messages and after the first message of the user. @@ -151,6 +169,13 @@ private void addMembersAfter(Collection messages, MessageContext contex context.addIds(memberIds); } + /** + * Finds the oldest message by the target member in the context. + * + * @param context the message context + * @param maxAge the maximum age of the message + * @return the oldest message instant + */ private Instant findOldestMessageByTarget(MessageContext context, Instant maxAge) { return context.rawMessages().stream() .filter(mes -> Verifier.equalSnowflake(mes.getAuthor(), context.user())) @@ -160,6 +185,14 @@ private Instant findOldestMessageByTarget(MessageContext context, Instant maxAge .orElse(maxAge); } + /** + * Gets the voice context for the specified message. + * + * @param target the target member + * @param message the message to determine channel, author, and start time + * @param settings the settings of the guild + * @return the message context + */ public MessageContext getVoiceContext(Member target, Message message, @Nullable Settings settings) { try { return voiceContextCache.get(message.getIdLong(), () -> retrieveVoiceContext(target, message, settings).resolve() @@ -170,6 +203,14 @@ public MessageContext getVoiceContext(Member target, Message message, @Nullable return MessageContext.byMessageAndMember(message, target); } + /** + * Retrieves the voice context for the specified message. + * + * @param target the target member + * @param message the message to determine channel, author, and start time + * @param settings the settings of the guild + * @return the message context + */ private MessageContext retrieveVoiceContext(Member target, Message message, @Nullable Settings settings) { var context = MessageContext.byMessageAndMember(message, target); var voiceState = target.getVoiceState(); @@ -193,10 +234,25 @@ private MessageContext retrieveVoiceContext(Member target, Message message, @Nul return context; } + /** + * Gets the combined context for the specified message. + * + * @param message the message to determine channel, author, and start time + * @param settings the settings of the guild + * @return the combined message context + */ public MessageContext getCombinedContext(Message message, @Nullable Settings settings) { return getCombinedContext(message.getMember(), message, settings); } + /** + * Gets the combined context for the specified member and message. + * + * @param target the target member + * @param message the message to determine channel, author, and start time + * @param settings the settings of the guild + * @return the combined message context + */ public MessageContext getCombinedContext(Member target, Message message, @Nullable Settings settings) { return getChannelContext(target, message, settings) .combine(getVoiceContext(target, message, settings)); diff --git a/src/main/java/de/chojo/repbot/analyzer/MessageAnalyzer.java b/src/main/java/de/chojo/repbot/analyzer/MessageAnalyzer.java index ed2a8d6e3..4e56f5ad7 100644 --- a/src/main/java/de/chojo/repbot/analyzer/MessageAnalyzer.java +++ b/src/main/java/de/chojo/repbot/analyzer/MessageAnalyzer.java @@ -37,9 +37,21 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Class responsible for analyzing messages to detect thankwords and their targets. + */ public class MessageAnalyzer { + /** + * The number of words to look around the thankword for potential targets. + */ private static final int LOOKAROUND = 6; + /** + * Logger instance for logging events. + */ private static final Logger log = getLogger(MessageAnalyzer.class); + /** + * Placeholder object for rejection cache. + */ private static final Object PLACEHOLDER = new Object(); private final ContextResolver contextResolver; private final Cache resultCache = CacheBuilder.newBuilder() @@ -53,6 +65,14 @@ public class MessageAnalyzer { private final Metrics metrics; private final Guilds guilds; + /** + * Constructs a new MessageAnalyzer. + * + * @param resolver the context resolver + * @param configuration the configuration instance + * @param metrics the metrics provider + * @param guilds the guilds provider + */ public MessageAnalyzer(ContextResolver resolver, Configuration configuration, Metrics metrics, Guilds guilds) { contextResolver = resolver; this.configuration = configuration; @@ -61,13 +81,12 @@ public MessageAnalyzer(ContextResolver resolver, Configuration configuration, Me } /** - * Analyze a message. + * Analyzes a message to detect thankwords and their targets. * - * @param pattern regex pattern for targetwords + * @param pattern regex pattern for thankwords * @param message message to analyze * @param settings settings of the guild - * @param limitTargets true if targets should be limited to users which have written in the channel in the - * maxHistoryAge + * @param limitTargets true if targets should be limited to users who have written in the channel in the maxHistoryAge * @param limit limit for returned matches in the analyzer result * @return analyzer results */ @@ -92,6 +111,13 @@ public AnalyzerResult processMessage(Pattern pattern, @NotNull Message message, return analyzer.log(message, AnalyzerResult.empty(EmptyResultReason.INTERNAL_ERROR)); } + /** + * Retrieves the thankword from the message using the provided pattern. + * + * @param message the message to analyze + * @param pattern the regex pattern for thankwords + * @return an optional containing the thankword if found, otherwise empty + */ @SuppressWarnings("DataFlowIssue") // We got no issues c: private Optional getThankword(Message message, Pattern pattern) { return CompletableFuture.supplyAsync(() -> { @@ -104,6 +130,16 @@ private Optional getThankword(Message message, Pattern pattern) { .join(); } + /** + * Analyzes the message to detect thankwords and their targets. + * + * @param pattern regex pattern for thankwords + * @param message message to analyze + * @param settings settings of the guild + * @param limitTargets true if targets should be limited to users who have written in the channel in the maxHistoryAge + * @param limit limit for returned matches in the analyzer result + * @return analyzer results + */ private AnalyzerResult analyze(Pattern pattern, Message message, @Nullable Settings settings, boolean limitTargets, int limit) { metrics.messages().countMessage(); if (pattern.pattern().isBlank()) return AnalyzerResult.empty(EmptyResultReason.NO_PATTERN); @@ -166,7 +202,17 @@ private AnalyzerResult analyze(Pattern pattern, Message message, @Nullable Setti return resolveMessage(match, message, pattern, context, limitTargets, limit); } - + /** + * Resolves the message to detect thankwords and their targets. + * + * @param matchPattern the matched thankword pattern + * @param message the message to analyze + * @param thankPattern the regex pattern for thankwords + * @param targets the message context containing potential targets + * @param limitTargets true if targets should be limited to users who have written in the channel in the maxHistoryAge + * @param limit limit for returned matches in the analyzer result + * @return analyzer results + */ private AnalyzerResult resolveMessage(String matchPattern, Message message, Pattern thankPattern, MessageContext targets, boolean limitTargets, int limit) { var contentRaw = message.getContentRaw(); diff --git a/src/main/java/de/chojo/repbot/analyzer/MessageContext.java b/src/main/java/de/chojo/repbot/analyzer/MessageContext.java index 01e172c9f..bdfe35168 100644 --- a/src/main/java/de/chojo/repbot/analyzer/MessageContext.java +++ b/src/main/java/de/chojo/repbot/analyzer/MessageContext.java @@ -18,6 +18,9 @@ import java.util.Set; import java.util.stream.Collectors; +/** + * Class representing the context of a message, including associated members, users, and messages. + */ public class MessageContext implements MemberHolder { private final Set userIds = new HashSet<>(); private final Set members = new HashSet<>(); @@ -27,49 +30,109 @@ public class MessageContext implements MemberHolder { private final Member target; private Message message; + /** + * Private constructor to initialize MessageContext with a message and target member. + * + * @param message the message associated with the context + * @param target the target member + */ private MessageContext(Message message, Member target) { this.message = message; this.target = target; } + /** + * Creates a MessageContext instance using the given message. + * + * @param message the message to create the context from + * @return a new MessageContext instance + */ public static MessageContext byMessage(Message message) { return new MessageContext(message, message.getMember()); } + /** + * Creates a MessageContext instance using the given message and member. + * + * @param message the message to create the context from + * @param member the member associated with the context + * @return a new MessageContext instance + */ public static MessageContext byMessageAndMember(Message message, Member member) { return new MessageContext(message, member); } + /** + * Adds a collection of user IDs to the context. + * + * @param ids the collection of user IDs to add + */ public void addIds(Collection ids) { userIds.addAll(ids); } + /** + * Adds a collection of members to the context. + * + * @param members the collection of members to add + */ public void addMembers(Collection members) { this.members.addAll(members); users.addAll(members.stream().map(Member::getUser).toList()); } + /** + * Adds a collection of raw messages to the context. + * + * @param messages the collection of raw messages to add + */ public void addRawMessages(Collection messages) { rawMessages.addAll(messages); } + /** + * Adds a collection of context messages to the context. + * + * @param messages the collection of context messages to add + */ public void addContextMessages(Collection messages) { contextMessages.addAll(messages); } + /** + * Adds a single member to the context. + * + * @param member the member to add + */ public void addMember(Member member) { members.add(member); users.add(member.getUser()); } + /** + * Adds a single raw message to the context. + * + * @param message the raw message to add + */ public void addRawMessage(Message message) { rawMessages.add(message); } + /** + * Adds a single context message to the context. + * + * @param message the context message to add + */ public void addContextMessage(Message message) { contextMessages.add(message); } + /** + * Combines another MessageContext into this one. + * + * @param context the MessageContext to combine with this one + * @return the combined MessageContext + */ public MessageContext combine(MessageContext context) { addIds(context.userIds); addRawMessages(context.rawMessages); @@ -78,32 +141,59 @@ public MessageContext combine(MessageContext context) { return this; } + /** + * Refreshes the context with a new message. + * + * @param message the new message to refresh the context with + * @return the refreshed MessageContext + */ protected MessageContext refresh(Message message) { this.message = message; return this; } + /** + * Gets the target member of the context. + * + * @return the target member + */ @Override public Member member() { return target; } + /** + * Gets an unmodifiable set of raw messages in the context. + * + * @return an unmodifiable set of raw messages + */ public Set rawMessages() { return Collections.unmodifiableSet(rawMessages); } + /** + * Gets an unmodifiable set of context messages in the context. + * + * @return an unmodifiable set of context messages + */ public Set contextMessages() { return Collections.unmodifiableSet(contextMessages); } + /** + * Gets the latest messages up to a specified limit. + * + * @param limit the maximum number of messages to retrieve + * @return a set of the latest messages + */ public Set latestMessages(int limit) { return rawMessages().stream().limit(limit).collect(Collectors.toCollection(LinkedHashSet::new)); } /** - * Resolves the guild members by the stored {@link #userIds} + * Resolves the guild members by the stored user IDs. * - * @return self for chaining + * @return the MessageContext for chaining */ public MessageContext resolve() { addMembers(userIds.stream() @@ -113,18 +203,38 @@ public MessageContext resolve() { return this; } + /** + * Gets an unmodifiable set of members in the context. + * + * @return an unmodifiable set of members + */ public Set members() { return Collections.unmodifiableSet(members); } + /** + * Gets the message associated with the context. + * + * @return the message + */ public Message message() { return message; } + /** + * Gets an unmodifiable set of users in the context. + * + * @return an unmodifiable set of users + */ public Set users() { return Collections.unmodifiableSet(users); } + /** + * Checks if the context is empty (i.e., has no members). + * + * @return true if the context is empty, false otherwise + */ public boolean isEmpty() { return members.isEmpty(); } diff --git a/src/main/java/de/chojo/repbot/analyzer/results/AnalyzerResult.java b/src/main/java/de/chojo/repbot/analyzer/results/AnalyzerResult.java index 0722e3f17..ba88a87b7 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/AnalyzerResult.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/AnalyzerResult.java @@ -20,40 +20,108 @@ import java.util.List; +/** + * Interface representing the result of an analyzer. + */ public interface AnalyzerResult { + /** + * Returns the result type. + * + * @return the result type + */ ResultType resultType(); + /** + * Casts this result to an EmptyAnalyzerResult. + * + * @return this result as an EmptyAnalyzerResult + */ default EmptyAnalyzerResult asEmpty() { return (EmptyAnalyzerResult) this; } + /** + * Casts this result to a MatchAnalyzerResult. + * + * @return this result as a MatchAnalyzerResult + */ default MatchAnalyzerResult asMatch() { return (MatchAnalyzerResult) this; } + /** + * Creates an empty analyzer result with the specified reason. + * + * @param resultReason the reason for the empty result + * @return the empty analyzer result + */ static AnalyzerResult empty(EmptyResultReason resultReason) { return new EmptyAnalyzerResult(null, resultReason); } + /** + * Creates an empty analyzer result with the specified match string and reason. + * + * @param match the match string + * @param resultReason the reason for the empty result + * @return the empty analyzer result + */ static AnalyzerResult empty(String match, EmptyResultReason resultReason) { return new EmptyAnalyzerResult(match, resultReason); } + /** + * Creates a direct analyzer result with the specified match string, donor, and receivers. + * + * @param match the match string + * @param donator the member who gave the thank + * @param receiver the list of members who received the thank + * @return the direct analyzer result + */ static AnalyzerResult mention(String match, Member donator, List receiver) { return new DirectAnalyzerResult(match, ThankType.MENTION, donator, receiver); } + /** + * Creates an answer analyzer result with the specified match string, donor, receiver, and reference message. + * + * @param match the match string + * @param donator the member who gave the thank + * @param receiver the member who received the thank + * @param referenceMessage the reference message + * @return the answer analyzer result + */ static AnalyzerResult answer(String match, Member donator, Member receiver, Message referenceMessage) { return new AnswerAnalyzerResult(match, donator, receiver, referenceMessage.getIdLong()); } + /** + * Creates a fuzzy analyzer result with the specified match string, thank words, member matches, donor, and receivers. + * + * @param match the match string + * @param thankwords the list of thank words + * @param memberMatches the list of member matches + * @param donator the member who gave the thank + * @param receivers the list of weighted entries of members who received the thank + * @return the fuzzy analyzer result + */ static AnalyzerResult fuzzy(String match, List thankwords, List memberMatches, Member donator, List> receivers) { return new FuzzyAnalyzerResult(match, thankwords, memberMatches, donator, receivers); } + /** + * Checks if the result is empty. + * + * @return true if the result is empty, false otherwise + */ default boolean isEmpty() { return resultType() == ResultType.NO_MATCH; } + /** + * Converts this result to a snapshot. + * + * @return the result snapshot + */ ResultSnapshot toSnapshot(); } diff --git a/src/main/java/de/chojo/repbot/analyzer/results/ResultType.java b/src/main/java/de/chojo/repbot/analyzer/results/ResultType.java index e9d73858d..c11437378 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/ResultType.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/ResultType.java @@ -5,7 +5,17 @@ */ package de.chojo.repbot.analyzer.results; +/** + * Enum representing the result types for analysis. + */ public enum ResultType { + /** + * Indicates that no match was found. + */ NO_MATCH, + + /** + * Indicates that a match was found. + */ MATCH } diff --git a/src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyAnalyzerResult.java b/src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyAnalyzerResult.java index 7b2a6c144..f84bd9854 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyAnalyzerResult.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyAnalyzerResult.java @@ -15,18 +15,41 @@ import javax.annotation.Nullable; +/** + * Represents an empty analyzer result with a match and a reason. + * + * @param match the matched string, can be null + * @param reason the reason for the empty result + */ public record EmptyAnalyzerResult(@Nullable String match, EmptyResultReason reason) implements AnalyzerResult, ResultSnapshot { + /** + * Returns the result type of this analyzer result. + * + * @return the result type, which is always {@link ResultType#NO_MATCH} + */ @Override public ResultType resultType() { return ResultType.NO_MATCH; } + /** + * Converts this analyzer result to a snapshot. + * + * @return this analyzer result as a snapshot + */ @Override public ResultSnapshot toSnapshot() { return this; } + /** + * Adds this analyzer result to the provided embed builder. + * + * @param guild the guild where the result was generated + * @param entry the result entry + * @param builder the localized embed builder to add the result to + */ @Override public void add(Guild guild, ResultEntry entry, LocalizedEmbedBuilder builder) { builder.setTitle(reason.localeKey()) diff --git a/src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyResultReason.java b/src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyResultReason.java index 2441f75ef..2b70c852c 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyResultReason.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyResultReason.java @@ -5,20 +5,56 @@ */ package de.chojo.repbot.analyzer.results.empty; +/** + * Enum representing the reasons for an empty result. + */ public enum EmptyResultReason { + /** + * No pattern was found. + */ NO_PATTERN("emptyresultreason.nopattern.description"), + + /** + * No match was found. + */ NO_MATCH("emptyresultreason.nomatch.description"), + + /** + * The reference message was not found. + */ REFERENCE_MESSAGE_NOT_FOUND("emptyresultreason.referencemessagenotfound.description"), + + /** + * The score was insufficient. + */ INSUFFICIENT_SCORE("emptyresultreason.insufficientscore.description"), + + /** + * An internal error occurred. + */ INTERNAL_ERROR("emptyresultreason.internalerror.description"), + + /** + * The target is not on the guild. + */ TARGET_NOT_ON_GUILD("emptyresultreason.targetnotonguild.description"); private final String localeKey; + /** + * Constructs an EmptyResultReason with the specified locale key. + * + * @param localeKey the locale key for the reason + */ EmptyResultReason(String localeKey) { this.localeKey = localeKey; } + /** + * Retrieves the locale key for the reason. + * + * @return the locale key + */ public String localeKey() { return localeKey; } diff --git a/src/main/java/de/chojo/repbot/analyzer/results/match/AnswerAnalyzerResult.java b/src/main/java/de/chojo/repbot/analyzer/results/match/AnswerAnalyzerResult.java index 4950ca61f..14d50e718 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/match/AnswerAnalyzerResult.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/match/AnswerAnalyzerResult.java @@ -13,31 +13,65 @@ import java.util.Collections; +/** + * Represents the result of an answer analyzer. + */ public class AnswerAnalyzerResult extends DirectAnalyzerResult { private final Message referenceMessage; private final long referenceMessageId; + /** + * Constructs an AnswerAnalyzerResult instance. + * + * @param match the match string + * @param donor the member who gave the thank + * @param receiver the member who received the thank + * @param referenceMessage the reference message + */ public AnswerAnalyzerResult(String match, Member donor, Member receiver, Message referenceMessage) { super(match, ThankType.ANSWER, donor, Collections.singletonList(receiver)); this.referenceMessage = referenceMessage; referenceMessageId = referenceMessage.getIdLong(); } + /** + * Constructs an AnswerAnalyzerResult instance with a reference message ID. + * + * @param match the match string + * @param donor the member who gave the thank + * @param receiver the member who received the thank + * @param referenceMessageId the ID of the reference message + */ public AnswerAnalyzerResult(String match, Member donor, Member receiver, long referenceMessageId) { super(match, ThankType.ANSWER, donor, Collections.singletonList(receiver)); referenceMessage = null; this.referenceMessageId = referenceMessageId; } + /** + * Returns the ID of the reference message. + * + * @return the ID of the reference message + */ public long referenceMessageId() { return referenceMessageId; } + /** + * Returns the reference message. + * + * @return the reference message, or null if not available + */ @Nullable public Message referenceMessage() { return referenceMessage; } + /** + * Converts this result to a snapshot. + * + * @return the result snapshot + */ @Override public ResultSnapshot toSnapshot() { return new AnswerResultSnapshot(donorId(), match(), receiverIds(), referenceMessageId); diff --git a/src/main/java/de/chojo/repbot/analyzer/results/match/DirectAnalyzerResult.java b/src/main/java/de/chojo/repbot/analyzer/results/match/DirectAnalyzerResult.java index 96ccf1675..0c3154c15 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/match/DirectAnalyzerResult.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/match/DirectAnalyzerResult.java @@ -11,23 +11,49 @@ import java.util.List; +/** + * Class representing the result of a direct analyzer match. + */ public class DirectAnalyzerResult extends MatchAnalyzerResult { private final List receivers; + /** + * Constructs a DirectAnalyzerResult instance. + * + * @param match the match string + * @param type the type of thank + * @param donor the member who gave the thank + * @param receivers the list of members who received the thank + */ public DirectAnalyzerResult(String match, ThankType type, Member donor, List receivers) { super(type, donor, match); this.receivers = receivers; } + /** + * Returns the list of receiver IDs. + * + * @return the list of receiver IDs + */ protected List receiverIds() { return receivers.stream().map(Member::getIdLong).toList(); } + /** + * Returns the list of members who received the thank. + * + * @return the list of members who received the thank + */ @Override public List receivers() { return receivers; } + /** + * Converts this result to a snapshot. + * + * @return the result snapshot + */ @Override public ResultSnapshot toSnapshot() { return new DirectResultSnapshot(thankType(), donorId(), match(), receiverIds()); diff --git a/src/main/java/de/chojo/repbot/analyzer/results/match/FuzzyAnalyzerResult.java b/src/main/java/de/chojo/repbot/analyzer/results/match/FuzzyAnalyzerResult.java index b41bdf6a5..009daeeff 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/match/FuzzyAnalyzerResult.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/match/FuzzyAnalyzerResult.java @@ -14,11 +14,23 @@ import java.util.List; import java.util.stream.Collectors; +/** + * Represents the result of a fuzzy match analysis. + */ public class FuzzyAnalyzerResult extends MatchAnalyzerResult { private final List thankwords; private final List memberMatches; private final List> weightedReceiver; + /** + * Constructs a new FuzzyAnalyzerResult. + * + * @param match the match string + * @param thankwords the list of thank words + * @param memberMatches the list of member matches + * @param donor the donor member + * @param weightedReceiver the list of weighted receiver entries + */ public FuzzyAnalyzerResult(String match, List thankwords, List memberMatches, Member donor, List> weightedReceiver) { super(ThankType.FUZZY, donor, match); this.thankwords = thankwords; @@ -26,25 +38,50 @@ public FuzzyAnalyzerResult(String match, List thankwords, List receivers() { return weightedReceiver.stream().map(WeightedEntry::getReference).collect(Collectors.toList()); } + /** + * Retrieves the list of weighted receiver entries. + * + * @return the list of weighted receiver entries + */ public List> weightedReceiver() { return weightedReceiver; } + /** + * Retrieves the list of member matches. + * + * @return the list of member matches + */ public List memberMatches() { return memberMatches; } + /** + * Retrieves the list of thank words. + * + * @return the list of thank words + */ public List thankwords() { return thankwords; } + /** + * Converts the result to a snapshot. + * + * @return the result snapshot + */ @Override public ResultSnapshot toSnapshot() { - return new FuzzyResultSnapshot(donorId(), match(),thankwords, memberMatches); + return new FuzzyResultSnapshot(donorId(), match(), thankwords, memberMatches); } } diff --git a/src/main/java/de/chojo/repbot/analyzer/results/match/MatchAnalyzerResult.java b/src/main/java/de/chojo/repbot/analyzer/results/match/MatchAnalyzerResult.java index 1ad5a09d7..5fea73c5d 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/match/MatchAnalyzerResult.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/match/MatchAnalyzerResult.java @@ -12,12 +12,22 @@ import java.util.List; +/** + * Abstract class representing the result of a match analyzer. + */ public abstract class MatchAnalyzerResult implements AnalyzerResult { private final ThankType thankType; private final Member donor; private final long donorId; private final String match; + /** + * Constructs a MatchAnalyzerResult instance. + * + * @param thankType the type of thank + * @param donor the member who gave the thank + * @param match the match string + */ public MatchAnalyzerResult(ThankType thankType, Member donor, String match) { this.thankType = thankType; this.donor = donor; @@ -25,37 +35,82 @@ public MatchAnalyzerResult(ThankType thankType, Member donor, String match) { this.match = match; } + /** + * Returns the match string. + * + * @return the match string + */ public String match() { return match; } + /** + * Returns the list of members who received the thank. + * + * @return the list of members who received the thank + */ public abstract List<@Nullable Member> receivers(); + /** + * Returns the member who gave the thank. + * + * @return the member who gave the thank, or null if not available + */ @Nullable public Member donor() { return donor; } + /** + * Returns the ID of the member who gave the thank. + * + * @return the ID of the member who gave the thank + */ public long donorId() { return donorId; } + /** + * Returns the type of thank. + * + * @return the type of thank + */ public ThankType thankType() { return thankType; } + /** + * Casts this result to an AnswerAnalyzerResult. + * + * @return this result as an AnswerAnalyzerResult + */ public AnswerAnalyzerResult asAnswer() { return (AnswerAnalyzerResult) this; } + /** + * Casts this result to a DirectAnalyzerResult. + * + * @return this result as a DirectAnalyzerResult + */ public DirectAnalyzerResult asMention() { return (DirectAnalyzerResult) this; } + /** + * Casts this result to a FuzzyAnalyzerResult. + * + * @return this result as a FuzzyAnalyzerResult + */ public FuzzyAnalyzerResult asFuzzy() { return (FuzzyAnalyzerResult) this; } + /** + * Returns the result type. + * + * @return the result type + */ @Override public ResultType resultType() { return ResultType.MATCH; diff --git a/src/main/java/de/chojo/repbot/analyzer/results/match/ThankType.java b/src/main/java/de/chojo/repbot/analyzer/results/match/ThankType.java index 6f93ca94b..9f120a2e4 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/match/ThankType.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/match/ThankType.java @@ -5,20 +5,56 @@ */ package de.chojo.repbot.analyzer.results.match; +/** + * Enum representing different types of thank actions. + */ public enum ThankType { + /** + * Fuzzy thank type. + */ FUZZY("thankType.fuzzy.name"), + + /** + * Mention thank type. + */ MENTION("thankType.mention.name"), + + /** + * Answer thank type. + */ ANSWER("thankType.answer.name"), + + /** + * Direct thank type. + */ DIRECT("thankType.direct.name"), + + /** + * Reaction thank type. + */ REACTION("thankType.reaction.name"), + + /** + * Embed thank type. + */ EMBED("thankType.embed.name"); private final String nameLocaleKey; + /** + * Constructs a new ThankType with the given locale key. + * + * @param nameLocaleKey the locale key associated with the thank type + */ ThankType(String nameLocaleKey) { this.nameLocaleKey = nameLocaleKey; } + /** + * Retrieves the locale key associated with the thank type. + * + * @return the locale key + */ public String nameLocaleKey() { return nameLocaleKey; } diff --git a/src/main/java/de/chojo/repbot/analyzer/results/match/fuzzy/MemberMatch.java b/src/main/java/de/chojo/repbot/analyzer/results/match/fuzzy/MemberMatch.java index 89710ee0d..f834f8bc4 100644 --- a/src/main/java/de/chojo/repbot/analyzer/results/match/fuzzy/MemberMatch.java +++ b/src/main/java/de/chojo/repbot/analyzer/results/match/fuzzy/MemberMatch.java @@ -8,12 +8,23 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +/** + * Represents a match result for a member with a word, name, nickname, and score. + */ public class MemberMatch { private final String word; private final String name; private final String nickname; private final double score; + /** + * Constructs a new MemberMatch with the specified word, name, nickname, and score. + * + * @param word the matched word + * @param name the member's name + * @param nickname the member's nickname + * @param score the match score + */ @JsonCreator public MemberMatch(@JsonProperty("word") String word, @JsonProperty("name") String name, @JsonProperty("nickname") String nickname, @JsonProperty("score") double score) { this.word = word; @@ -22,22 +33,47 @@ public MemberMatch(@JsonProperty("word") String word, @JsonProperty("name") Stri this.score = score; } + /** + * Returns the matched word. + * + * @return the matched word + */ public String word() { return word; } + /** + * Returns the member's name. + * + * @return the member's name + */ public String name() { return name; } + /** + * Returns the member's nickname. + * + * @return the member's nickname + */ public String nickname() { return nickname; } + /** + * Returns the match score. + * + * @return the match score + */ public double score() { return score; } + /** + * Returns a string representation of the match result. + * + * @return a string representation of the match result + */ public String asString() { return "`%s` ➜ %s (%s) | Score %.03f".formatted(word, name, nickname, score); } diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/AbuseProtection.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/AbuseProtection.java index 7a20dbf48..2d9e028fb 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/AbuseProtection.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/AbuseProtection.java @@ -23,7 +23,16 @@ import java.time.temporal.ChronoUnit; +/** + * Slash command for managing abuse protection settings. + */ public class AbuseProtection extends SlashCommand { + + /** + * Constructs an AbuseProtection command with the specified guilds provider. + * + * @param guilds the guilds provider + */ public AbuseProtection(Guilds guilds) { super(Slash.of("abuseprotection", "command.abuseprotection.description") .adminCommand() @@ -40,13 +49,11 @@ public AbuseProtection(Guilds guilds) { .handler(new MaxMessageReputation(guilds)) .argument(Argument.integer("amount", "command.abuseprotection.message.reputation.options.amount.description") .min(1) - // The max amount of components without delete button .max(49))) .subCommand(SubCommand.of("min", "command.abuseprotection.message.min.description") .handler(new MinMessages(guilds)) .argument(Argument.integer("messages", "command.abuseprotection.message.min.options.messages.description") .min(0) - // The max amount of retrieved history .max(100)))) .group(Group.of("context", "command.abuseprotection.context.description") .subCommand(SubCommand.of("donor", "command.abuseprotection.context.donor.description") diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/Info.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/Info.java index 9c0d81e1f..4a169cad7 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/Info.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/Info.java @@ -18,18 +18,39 @@ import static de.chojo.repbot.util.Text.getSetting; +/** + * Handler for the abuse protection info command. + */ public class Info implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Info handler. + * + * @param guilds the Guilds provider + */ public Info(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { event.replyEmbeds(getSettings(context, guilds.guild(event.getGuild()))).queue(); } + /** + * Retrieves the abuse protection settings for the specified guild. + * + * @param context the EventContext + * @param guild the RepGuild instance + * @return a MessageEmbed containing the settings + */ private MessageEmbed getSettings(EventContext context, RepGuild guild) { var abuseProt = guild.settings().abuseProtection(); var setting = List.of( diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/context/DonorContext.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/context/DonorContext.java index 01d375c48..e1a2d7971 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/context/DonorContext.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/context/DonorContext.java @@ -11,13 +11,27 @@ import de.chojo.repbot.util.Text; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the donor context for abuse protection commands. + */ public class DonorContext implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new DonorContext handler. + * + * @param guilds the Guilds provider + */ public DonorContext(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = guilds.guild(event.getGuild()); @@ -33,6 +47,5 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont event.reply(Text.getBooleanMessage(context, abuseSettings.donorContext(state), "command.abuseprotection.context.donor.message.true", "command.abuseprotection.context.donor.message.false")) .queue(); - } } diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/context/ReceiverContext.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/context/ReceiverContext.java index ffd83e761..5da2fa7a8 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/context/ReceiverContext.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/context/ReceiverContext.java @@ -11,13 +11,27 @@ import de.chojo.repbot.util.Text; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the receiver context command for abuse protection. + */ public class ReceiverContext implements SlashHandler { private final Guilds guilds; + /** + * Constructs a ReceiverContext handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public ReceiverContext(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = guilds.guild(event.getGuild()); diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/Cooldown.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/Cooldown.java index 32f7c4381..841632377 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/Cooldown.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/Cooldown.java @@ -11,13 +11,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the cooldown limit for abuse protection commands. + */ public class Cooldown implements SlashHandler { private final Guilds guilds; + /** + * Constructs a Cooldown handler with the specified guild provider. + * + * @param guilds the guild provider + */ public Cooldown(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for setting or getting the cooldown limit. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = guilds.guild(event.getGuild()); @@ -31,6 +45,5 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont event.reply(context.localize("command.abuseprotection.limit.cooldown.message.set", Replacement.create("MINUTES", abuseSettings.cooldown((int) cooldown)))).queue(); - } } diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/DonorLimit.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/DonorLimit.java index 3d48048ed..610ed08be 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/DonorLimit.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/DonorLimit.java @@ -11,13 +11,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the donor limit slash command. + */ public class DonorLimit implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new DonorLimit instance. + * + * @param guilds the guilds provider + */ public DonorLimit(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = guilds.guild(event.getGuild()); diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/ReceiverLimit.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/ReceiverLimit.java index 267d086b2..073b33138 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/ReceiverLimit.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/limit/ReceiverLimit.java @@ -11,13 +11,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the receiver limit command for abuse protection. + */ public class ReceiverLimit implements SlashHandler { private final Guilds guilds; + /** + * Constructs a ReceiverLimit handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public ReceiverLimit(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = guilds.guild(event.getGuild()); diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MaxMessageAge.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MaxMessageAge.java index a82f7f075..87c0c3927 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MaxMessageAge.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MaxMessageAge.java @@ -11,13 +11,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the max message age command in abuse protection. + */ public class MaxMessageAge implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new MaxMessageAge handler with the specified Guilds provider. + * + * @param guilds the Guilds provider + */ public MaxMessageAge(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for setting or getting the max message age. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = guilds.guild(event.getGuild()); diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MaxMessageReputation.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MaxMessageReputation.java index b60bfdb44..e5ee3d884 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MaxMessageReputation.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MaxMessageReputation.java @@ -11,13 +11,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the max message reputation command in abuse protection. + */ public class MaxMessageReputation implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new MaxMessageReputation handler with the specified Guilds provider. + * + * @param guilds the Guilds provider + */ public MaxMessageReputation(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for setting or getting the max message reputation. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = guilds.guild(event.getGuild()); diff --git a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MinMessages.java b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MinMessages.java index 2feae4837..82a96e151 100644 --- a/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MinMessages.java +++ b/src/main/java/de/chojo/repbot/commands/abuseprotection/handler/message/MinMessages.java @@ -11,13 +11,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the minimum messages command for abuse protection. + */ public class MinMessages implements SlashHandler { private final Guilds guilds; + /** + * Constructs a MinMessages handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public MinMessages(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for setting or getting the minimum messages for abuse protection. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = guilds.guild(event.getGuild()); diff --git a/src/main/java/de/chojo/repbot/commands/bot/BotAdmin.java b/src/main/java/de/chojo/repbot/commands/bot/BotAdmin.java index a5d909fed..92c9470b3 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/BotAdmin.java +++ b/src/main/java/de/chojo/repbot/commands/bot/BotAdmin.java @@ -27,7 +27,17 @@ import de.chojo.repbot.dao.provider.Guilds; import de.chojo.repbot.statistic.Statistic; +/** + * Class representing bot admin commands. + */ public class BotAdmin extends SlashCommand { + /** + * Constructs a BotAdmin instance with the specified guilds, configuration, and statistics. + * + * @param guilds the guilds provider + * @param configuration the configuration + * @param statistics the statistics + */ public BotAdmin(Guilds guilds, Configuration configuration, Statistic statistics) { super(Slash.of("bot", "Bot admin commands.") .unlocalized() diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/Debug.java b/src/main/java/de/chojo/repbot/commands/bot/handler/Debug.java index 4c61bca91..65fb2d15b 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/Debug.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/Debug.java @@ -34,13 +34,27 @@ import static de.chojo.jdautil.util.Guilds.prettyName; +/** + * Handles the slash command for debugging information about a guild. + */ public class Debug implements SlashHandler { private final Guilds guilds; + /** + * Constructs a Debug handler with the specified guild provider. + * + * @param guilds the guild provider + */ public Debug(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to provide debugging information about a guild. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guildId = event.getOption("guild_id").getAsLong(); @@ -156,10 +170,22 @@ public CompletableFuture buildPage() { context.registerPage(pages, true); } + /** + * Formats a LocalDateTime as a timestamp. + * + * @param dateTime the LocalDateTime to format + * @return the formatted timestamp + */ private String timestamp(LocalDateTime dateTime) { return TimeFormat.DATE_TIME_SHORT.format(dateTime.toEpochSecond(ZoneOffset.UTC) * 1000); } + /** + * Formats an OffsetDateTime as a timestamp. + * + * @param dateTime the OffsetDateTime to format + * @return the formatted timestamp + */ private String timestamp(OffsetDateTime dateTime) { return TimeFormat.DATE_TIME_SHORT.format(dateTime.toEpochSecond() * 1000); } diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/InvalidateCache.java b/src/main/java/de/chojo/repbot/commands/bot/handler/InvalidateCache.java index 8cb2759a9..9f9c2b109 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/InvalidateCache.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/InvalidateCache.java @@ -10,14 +10,28 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the invalidate cache command. + */ public class InvalidateCache implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new InvalidateCache handler. + * + * @param guilds the Guilds provider + */ public InvalidateCache(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to invalidate the guild cache. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { guilds.invalidate(event.getOption("guild").getAsLong()); diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/Leave.java b/src/main/java/de/chojo/repbot/commands/bot/handler/Leave.java index 862e4eaa7..8a9eb96fc 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/Leave.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/Leave.java @@ -10,7 +10,23 @@ import de.chojo.jdautil.wrapper.EventContext; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the leave command. + */ public class Leave implements SlashHandler { + + /** + * Creates a new leave handler. + */ + public Leave(){ + } + + /** + * Handles the slash command interaction event to leave a guild. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = event.getJDA().getShardManager().getGuildById(event.getOption("guild_id").getAsLong()); diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/Redeploy.java b/src/main/java/de/chojo/repbot/commands/bot/handler/Redeploy.java index f74f8fee9..646b0a1be 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/Redeploy.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/Redeploy.java @@ -10,10 +10,25 @@ import de.chojo.jdautil.wrapper.EventContext; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the redeploy command for refreshing guild commands. + */ public class Redeploy implements SlashHandler { + + /** + * Creates a new redeploy handler. + */ + public Redeploy(){ + } + + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { - var guild = event.getJDA().getShardManager().getGuildById(event.getOption("guild_id").getAsLong()); if (guild == null) { diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/Search.java b/src/main/java/de/chojo/repbot/commands/bot/handler/Search.java index 5738a2b27..bf3e608d5 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/Search.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/Search.java @@ -13,7 +13,22 @@ import java.util.Locale; import java.util.stream.Collectors; +/** + * Handler for the search slash command. + */ public class Search implements SlashHandler { + + /** + * Creates a new search handler. + */ + public Search(){ + } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var term = event.getOption("term").getAsString().toLowerCase(Locale.ROOT); diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/SharedGuilds.java b/src/main/java/de/chojo/repbot/commands/bot/handler/SharedGuilds.java index 3e3f5c7a5..d80737397 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/SharedGuilds.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/SharedGuilds.java @@ -17,13 +17,28 @@ import java.util.ArrayList; import java.util.stream.Collectors; +/** + * Handler for the "shared guilds" slash command. + * This command finds and lists the guilds shared between the bot and a specified user. + */ public class SharedGuilds implements SlashHandler { private final Configuration configuration; + /** + * Constructs a new SharedGuilds handler. + * + * @param configuration the bot configuration + */ public SharedGuilds(Configuration configuration) { this.configuration = configuration; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var userOpt = event.getOption("user"); diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/log/Analyzer.java b/src/main/java/de/chojo/repbot/commands/bot/handler/log/Analyzer.java index 1ca30ed2c..126b586ab 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/log/Analyzer.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/log/Analyzer.java @@ -12,13 +12,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the "analyzer" slash command. + */ public class Analyzer extends BaseAnalyzer implements SlashHandler { private final Guilds guilds; + /** + * Constructs an Analyzer handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Analyzer(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild_id = ValueParser.parseLong(event.getOption("guild_id").getAsString()); diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Metrics.java b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Metrics.java index 12f809938..9faf1d099 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Metrics.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Metrics.java @@ -18,13 +18,27 @@ import java.util.List; import java.util.concurrent.CompletableFuture; +/** + * Handles the metrics-related slash commands. + */ public class Metrics implements SlashHandler { private final Configuration configuration; + /** + * Constructs a new Metrics handler with the specified configuration. + * + * @param configuration the configuration to use + */ public Metrics(Configuration configuration) { this.configuration = configuration; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { List links = new ArrayList<>(); @@ -58,6 +72,12 @@ public CompletableFuture buildPage() { }); } + /** + * Constructs a URL for the specified endpoint. + * + * @param endpoint the endpoint to construct the URL for + * @return the constructed URL + */ private String url(String endpoint) { return "%s/v1/metrics/%s".formatted(configuration.api().url(), endpoint); } diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Reload.java b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Reload.java index 376a874df..5792591cd 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Reload.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Reload.java @@ -11,14 +11,28 @@ import de.chojo.repbot.config.exception.ConfigurationException; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the reload command for reloading the bot's configuration. + */ public class Reload implements SlashHandler { private final Configuration configuration; + /** + * Constructs a Reload handler with the specified configuration. + * + * @param configuration the configuration to be reloaded + */ public Reload(Configuration configuration) { this.configuration = configuration; } + /** + * Handles the slash command interaction event for reloading the configuration. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { try { diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Restart.java b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Restart.java index 82d996ee3..a1054cb77 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Restart.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Restart.java @@ -14,14 +14,28 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Handler for the restart command. + */ public class Restart implements SlashHandler { private static final Logger log = getLogger(Restart.class); private final Configuration configuration; + /** + * Constructs a new Restart handler with the specified configuration. + * + * @param configuration the configuration + */ public Restart(Configuration configuration) { this.configuration = configuration; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { if (!configuration.baseSettings().isOwner(event.getUser().getIdLong())) { diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Shudown.java b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Shudown.java index 619f12ac4..d6d62c981 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Shudown.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Shudown.java @@ -14,14 +14,29 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Handler for the "shutdown" slash command. + * This command shuts down the bot if the user is the owner. + */ public class Shudown implements SlashHandler { private static final Logger log = getLogger(Shudown.class); private final Configuration configuration; + /** + * Constructs a new Shudown handler. + * + * @param configuration the bot configuration + */ public Shudown(Configuration configuration) { this.configuration = configuration; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { if (!configuration.baseSettings().isOwner(event.getUser().getIdLong())) { diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Status.java b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Status.java index 33da22508..2f28208ab 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Status.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Status.java @@ -11,13 +11,27 @@ import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the status slash command. + */ public class Status implements SlashHandler { private final Statistic statistic; + /** + * Constructs a new Status handler. + * + * @param statistic the statistic object used to retrieve system statistics + */ public Status(Statistic statistic) { this.statistic = statistic; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var builder = new EmbedBuilder(); diff --git a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Upgrade.java b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Upgrade.java index 86e82996f..bcd02b6d3 100644 --- a/src/main/java/de/chojo/repbot/commands/bot/handler/system/Upgrade.java +++ b/src/main/java/de/chojo/repbot/commands/bot/handler/system/Upgrade.java @@ -14,14 +14,35 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Handler for the upgrade slash command. + */ public class Upgrade implements SlashHandler { + /** + * Logger instance for logging events. + */ private static final Logger log = getLogger(Upgrade.class); + + /** + * Configuration object for accessing base settings. + */ private final Configuration configuration; + /** + * Constructs a new Upgrade handler. + * + * @param configuration the configuration object used to access base settings + */ public Upgrade(Configuration configuration) { this.configuration = configuration; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { if (!configuration.baseSettings().isOwner(event.getUser().getIdLong())) { diff --git a/src/main/java/de/chojo/repbot/commands/channel/Channel.java b/src/main/java/de/chojo/repbot/commands/channel/Channel.java index 40c82c359..ca328df89 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/Channel.java +++ b/src/main/java/de/chojo/repbot/commands/channel/Channel.java @@ -21,7 +21,15 @@ import de.chojo.repbot.commands.channel.handler.announcement.State; import de.chojo.repbot.dao.provider.Guilds; +/** + * Class representing channel commands. + */ public class Channel extends SlashCommand { + /** + * Constructs a Channel instance with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Channel(Guilds guilds) { super(Slash.of("channel", "command.channel.description") .adminCommand() diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/Add.java b/src/main/java/de/chojo/repbot/commands/channel/handler/Add.java index 1be0fb21d..1e3d62c02 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/Add.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/Add.java @@ -13,20 +13,44 @@ import net.dv8tion.jda.api.entities.channel.middleman.StandardGuildChannel; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the "add channel" slash command, which adds a channel to the thanking channels. + */ public class Add extends BaseChannelModifier { + + /** + * Constructs an Add handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Add(Guilds guilds) { super(guilds); } + /** + * Adds a text channel to the thanking channels. + * + * @param event the slash command interaction event + * @param context the event context + * @param channels the channels settings + * @param channel the text channel to add + */ @Override public void textChannel(SlashCommandInteractionEvent event, EventContext context, Channels channels, StandardGuildChannel channel) { channels.add(channel); event.getHook().editOriginal( context.localize("command.channel.add.message.added", Replacement.create("CHANNEL", channel.getAsMention()))).queue(); - } + /** + * Adds a category to the thanking channels. + * + * @param event the slash command interaction event + * @param context the event context + * @param channels the channels settings + * @param category the category to add + */ @Override public void category(SlashCommandInteractionEvent event, EventContext context, Channels channels, Category category) { channels.add(category); diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/BaseChannelModifier.java b/src/main/java/de/chojo/repbot/commands/channel/handler/BaseChannelModifier.java index 63ceef95d..dbe2369a6 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/BaseChannelModifier.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/BaseChannelModifier.java @@ -16,6 +16,9 @@ import java.util.Set; +/** + * Abstract base class for handling slash commands that modify channels. + */ public abstract class BaseChannelModifier implements SlashHandler { private static final java.util.Set ALLOWED_CHANNEL = Set.of(ChannelType.TEXT, ChannelType.FORUM, ChannelType.CATEGORY, ChannelType.VOICE); @@ -23,10 +26,21 @@ public abstract class BaseChannelModifier implements SlashHandler { Set.of(ChannelType.TEXT, ChannelType.FORUM, ChannelType.VOICE); private final Guilds guilds; + /** + * Constructs a BaseChannelModifier with the specified guilds provider. + * + * @param guilds the guilds provider + */ public BaseChannelModifier(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var channels = guilds.guild(event.getGuild()).settings().thanking().channels(); @@ -46,7 +60,23 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont } } + /** + * Abstract method to handle text channel modification. + * + * @param event the slash command interaction event + * @param context the event context + * @param channels the channels settings + * @param channel the text channel to modify + */ public abstract void textChannel(SlashCommandInteractionEvent event, EventContext context, Channels channels, StandardGuildChannel channel); + /** + * Abstract method to handle category modification. + * + * @param event the slash command interaction event + * @param context the event context + * @param channels the channels settings + * @param category the category to modify + */ public abstract void category(SlashCommandInteractionEvent event, EventContext context, Channels channels, Category category); } diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/List.java b/src/main/java/de/chojo/repbot/commands/channel/handler/List.java index 0d3080596..8046ef0fd 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/List.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/List.java @@ -17,20 +17,41 @@ import java.util.stream.Collectors; +/** + * Handler for the list channels command. + */ public class List implements SlashHandler { private static final String MORE = String.format("$%s$", "command.channel.list.message.more"); private final Guilds guilds; + /** + * Constructs a new List handler. + * + * @param guilds the Guilds provider + */ public List(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to list channels. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var channels = guilds.guild(event.getGuild()).settings().thanking().channels(); event.replyEmbeds(getChannelList(channels, context)).queue(); } + /** + * Generates a MessageEmbed containing the list of channels and categories. + * + * @param channels the Channels instance containing the channel and category data + * @param context the EventContext + * @return a MessageEmbed with the list of channels and categories + */ private MessageEmbed getChannelList(Channels channels, EventContext context) { var channelNames = channels.channels().stream() diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/ListType.java b/src/main/java/de/chojo/repbot/commands/channel/handler/ListType.java index d726e494e..c87c85aa1 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/ListType.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/ListType.java @@ -12,13 +12,27 @@ import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the list type command. + */ public class ListType implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new ListType handler with the specified Guilds provider. + * + * @param guilds the Guilds provider + */ public ListType(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to list the type of channels. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var channels = guilds.guild(event.getGuild()).settings().thanking().channels(); @@ -35,6 +49,12 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont .queue(); } + /** + * Handles the auto-complete interaction event for the list type command. + * + * @param event the CommandAutoCompleteInteractionEvent + * @param context the EventContext + */ @Override public void onAutoComplete(CommandAutoCompleteInteractionEvent event, EventContext context) { if ("type".equals(event.getFocusedOption().getName())) { diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/Remove.java b/src/main/java/de/chojo/repbot/commands/channel/handler/Remove.java index a93f1023e..184a97ade 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/Remove.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/Remove.java @@ -13,11 +13,28 @@ import net.dv8tion.jda.api.entities.channel.middleman.StandardGuildChannel; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the removal of channels from a guild's settings. + */ public class Remove extends BaseChannelModifier { + + /** + * Constructs a Remove handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Remove(Guilds guilds) { super(guilds); } + /** + * Handles the removal of a text channel from the guild's settings. + * + * @param event the slash command interaction event + * @param context the event context + * @param channels the channels settings + * @param channel the text channel to remove + */ @Override public void textChannel(SlashCommandInteractionEvent event, EventContext context, Channels channels, StandardGuildChannel channel) { channels.remove(channel); @@ -26,6 +43,14 @@ public void textChannel(SlashCommandInteractionEvent event, EventContext context Replacement.create("CHANNEL", channel.getAsMention()))).queue(); } + /** + * Handles the removal of a category from the guild's settings. + * + * @param event the slash command interaction event + * @param context the event context + * @param channels the channels settings + * @param category the category to remove + */ @Override public void category(SlashCommandInteractionEvent event, EventContext context, Channels channels, Category category) { channels.remove(category); diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/Set.java b/src/main/java/de/chojo/repbot/commands/channel/handler/Set.java index 25e1dd87c..62187f672 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/Set.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/Set.java @@ -13,11 +13,28 @@ import net.dv8tion.jda.api.entities.channel.middleman.StandardGuildChannel; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the "set channel" slash command. + * This command sets the text channel or category for the guild's settings. + */ public class Set extends BaseChannelModifier { + /** + * Constructs a new Set handler. + * + * @param guilds the guilds provider + */ public Set(Guilds guilds) { super(guilds); } + /** + * Sets the text channel for the guild's settings. + * + * @param event the slash command interaction event + * @param context the event context + * @param channels the channels settings + * @param channel the text channel to set + */ @Override public void textChannel(SlashCommandInteractionEvent event, EventContext context, Channels channels, StandardGuildChannel channel) { channels.clearChannel(); @@ -27,6 +44,14 @@ public void textChannel(SlashCommandInteractionEvent event, EventContext context Replacement.create("CHANNEL", channel.getAsMention()))).queue(); } + /** + * Sets the category for the guild's settings. + * + * @param event the slash command interaction event + * @param context the event context + * @param channels the channels settings + * @param category the category to set + */ @Override public void category(SlashCommandInteractionEvent event, EventContext context, Channels channels, Category category) { channels.clearCategories(); diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Info.java b/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Info.java index 32822f75c..61b5a7463 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Info.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Info.java @@ -12,13 +12,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the announcement info command. + */ public class Info implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Info handler. + * + * @param guilds the Guilds provider + */ public Info(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var announcements = guilds.guild(event.getGuild()).settings().announcements(); diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Location.java b/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Location.java index 2329dcc0c..61373bf28 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Location.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Location.java @@ -12,13 +12,27 @@ import net.dv8tion.jda.api.entities.channel.ChannelType; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for setting the announcement channel location. + */ public class Location implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Location handler with the specified Guilds provider. + * + * @param guilds the Guilds provider + */ public Location(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to set the announcement channel location. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var announcements = guilds.guild(event.getGuild()).settings().announcements(); diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/State.java b/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/State.java index 2735883b1..b6aa8d15b 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/State.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/State.java @@ -11,13 +11,28 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.commands.OptionMapping; +/** + * Handler for the "announcement state" slash command. + * This command sets the active state of announcements for the guild. + */ public class State implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new State handler. + * + * @param guilds the guilds provider + */ public State(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var announcements = guilds.guild(event.getGuild()).settings().announcements(); diff --git a/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Where.java b/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Where.java index b9e81268c..85b618984 100644 --- a/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Where.java +++ b/src/main/java/de/chojo/repbot/commands/channel/handler/announcement/Where.java @@ -13,13 +13,27 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.commands.OptionMapping; +/** + * Handler for the "Where" slash command. + */ public class Where implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Where handler. + * + * @param guilds the guilds provider + */ public Where(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var announcements = guilds.guild(event.getGuild()).settings().announcements(); @@ -30,6 +44,12 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont } } + /** + * Handles the auto-complete interaction event. + * + * @param event the auto-complete interaction event + * @param context the event context + */ @Override public void onAutoComplete(CommandAutoCompleteInteractionEvent event, EventContext context) { if ("where".equals(event.getFocusedOption().getName())) { diff --git a/src/main/java/de/chojo/repbot/commands/dashboard/Dashboard.java b/src/main/java/de/chojo/repbot/commands/dashboard/Dashboard.java index 72af9334f..40dca58da 100644 --- a/src/main/java/de/chojo/repbot/commands/dashboard/Dashboard.java +++ b/src/main/java/de/chojo/repbot/commands/dashboard/Dashboard.java @@ -10,7 +10,15 @@ import de.chojo.repbot.commands.dashboard.handler.Show; import de.chojo.repbot.dao.provider.Guilds; +/** + * Represents the Dashboard command. + */ public class Dashboard extends SlashCommand { + /** + * Constructs a new Dashboard command. + * + * @param guilds the Guilds provider + */ public Dashboard(Guilds guilds) { super(Slash.of("dashboard", "command.dashboard.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/dashboard/handler/Show.java b/src/main/java/de/chojo/repbot/commands/dashboard/handler/Show.java index 5c6586ad1..abcc9f047 100644 --- a/src/main/java/de/chojo/repbot/commands/dashboard/handler/Show.java +++ b/src/main/java/de/chojo/repbot/commands/dashboard/handler/Show.java @@ -18,18 +18,40 @@ import java.util.stream.Collectors; +/** + * Handler for the "show dashboard" slash command. + * This command displays a dashboard with various statistics and rankings for the guild. + */ public class Show implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Show handler. + * + * @param guilds the guilds provider + */ public Show(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { event.replyEmbeds(getDashboard(event.getGuild(), context)).queue(); } + /** + * Generates the dashboard embed message for the guild. + * + * @param guild the guild for which the dashboard is generated + * @param context the event context + * @return the dashboard embed message + */ private MessageEmbed getDashboard(Guild guild, EventContext context) { var reputation = guilds.guild(guild).reputation(); var stats = reputation.stats(); diff --git a/src/main/java/de/chojo/repbot/commands/debug/Debug.java b/src/main/java/de/chojo/repbot/commands/debug/Debug.java index 70bcea5a2..4f27ccf6c 100644 --- a/src/main/java/de/chojo/repbot/commands/debug/Debug.java +++ b/src/main/java/de/chojo/repbot/commands/debug/Debug.java @@ -10,8 +10,16 @@ import de.chojo.repbot.commands.debug.handler.Show; import de.chojo.repbot.dao.provider.Guilds; +/** + * Represents the debug command for the bot. + */ public class Debug extends SlashCommand { + /** + * Constructs a new Debug instance. + * + * @param guilds the guilds provider + */ public Debug(Guilds guilds) { super(Slash.of("debug", "command.debug.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/debug/handler/Show.java b/src/main/java/de/chojo/repbot/commands/debug/handler/Show.java index b06897f6b..e36b52bc1 100644 --- a/src/main/java/de/chojo/repbot/commands/debug/handler/Show.java +++ b/src/main/java/de/chojo/repbot/commands/debug/handler/Show.java @@ -17,13 +17,27 @@ import static de.chojo.repbot.util.Guilds.prettyName; +/** + * Handler for the debug show slash command. + */ public class Show implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Show handler. + * + * @param guilds the guilds provider + */ public Show(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var settings = guilds.guild(event.getGuild()).settings(); diff --git a/src/main/java/de/chojo/repbot/commands/gdpr/Gdpr.java b/src/main/java/de/chojo/repbot/commands/gdpr/Gdpr.java index b1368cda2..c13b452c7 100644 --- a/src/main/java/de/chojo/repbot/commands/gdpr/Gdpr.java +++ b/src/main/java/de/chojo/repbot/commands/gdpr/Gdpr.java @@ -11,8 +11,16 @@ import de.chojo.repbot.commands.gdpr.handler.Delete; import de.chojo.repbot.commands.gdpr.handler.Request; +/** + * Represents the GDPR command with subcommands for requesting and deleting data. + */ public class Gdpr extends SlashCommand { + /** + * Constructs a new GDPR command. + * + * @param gdpr the GDPR data access object + */ public Gdpr(de.chojo.repbot.dao.access.Gdpr gdpr) { super(Slash.of("gdpr", "command.gdpr.description") .subCommand(SubCommand.of("request", "command.gdpr.request.description") diff --git a/src/main/java/de/chojo/repbot/commands/gdpr/handler/Delete.java b/src/main/java/de/chojo/repbot/commands/gdpr/handler/Delete.java index ec9abb675..4c614467b 100644 --- a/src/main/java/de/chojo/repbot/commands/gdpr/handler/Delete.java +++ b/src/main/java/de/chojo/repbot/commands/gdpr/handler/Delete.java @@ -13,14 +13,28 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Handles the slash command for GDPR delete requests. + */ public class Delete implements SlashHandler { private final Gdpr gdpr; private static final Logger log = getLogger(Delete.class); + /** + * Constructs a Delete handler with the specified GDPR access object. + * + * @param gdpr the GDPR access object + */ public Delete(Gdpr gdpr) { this.gdpr = gdpr; } + /** + * Handles the slash command interaction event to process a GDPR delete request. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var success = gdpr.request(event.getUser()).queueDeletion(); diff --git a/src/main/java/de/chojo/repbot/commands/gdpr/handler/Request.java b/src/main/java/de/chojo/repbot/commands/gdpr/handler/Request.java index 3d6078017..ea0a7300a 100644 --- a/src/main/java/de/chojo/repbot/commands/gdpr/handler/Request.java +++ b/src/main/java/de/chojo/repbot/commands/gdpr/handler/Request.java @@ -10,13 +10,27 @@ import de.chojo.repbot.dao.access.Gdpr; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the GDPR request command. + */ public class Request implements SlashHandler { private final Gdpr gdpr; + /** + * Constructs a new Request handler with the specified GDPR data access object. + * + * @param gdpr the GDPR data access object + */ public Request(Gdpr gdpr) { this.gdpr = gdpr; } + /** + * Handles the slash command interaction event to process a GDPR request. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { event.deferReply(true).queue(); diff --git a/src/main/java/de/chojo/repbot/commands/info/Info.java b/src/main/java/de/chojo/repbot/commands/info/Info.java index 460ae77da..edfebc5da 100644 --- a/src/main/java/de/chojo/repbot/commands/info/Info.java +++ b/src/main/java/de/chojo/repbot/commands/info/Info.java @@ -16,14 +16,29 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Command class for the info command. + */ public class Info extends SlashCommand { private static final Logger log = getLogger(Info.class); + /** + * Constructs a new Info command. + * + * @param version the version of the application + * @param configuration the configuration of the application + */ private Info(String version, Configuration configuration) { super(Slash.of("info", "command.info.description") .command(new Show(version, configuration))); } + /** + * Creates a new Info command instance. + * + * @param configuration the configuration of the application + * @return a new Info command instance + */ public static Info create(Configuration configuration) { var version = "undefined"; try (var input = Info.class.getClassLoader().getResourceAsStream("version")) { diff --git a/src/main/java/de/chojo/repbot/commands/info/handler/Show.java b/src/main/java/de/chojo/repbot/commands/info/handler/Show.java index 85b67025a..b53571ad3 100644 --- a/src/main/java/de/chojo/repbot/commands/info/handler/Show.java +++ b/src/main/java/de/chojo/repbot/commands/info/handler/Show.java @@ -36,6 +36,10 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Handler for the "show info" slash command. + * This command displays information about the bot, including contributors, version, and support links. + */ public class Show implements SlashHandler { private static final String ART = "**SmartieFox ☆*:.。.o(≧▽≦)o.。.:*☆**\n[Twitter](https://twitter.com/smartiefoxart) [Twitch](https://www.twitch.tv/smartiefox)"; private static final String SOURCE = "[rainbowdashlabs/reputation-bot](https://github.com/rainbowdashlabs/reputation-bot)"; @@ -49,16 +53,35 @@ public class Show implements SlashHandler { private String contributors; private Instant lastFetch = Instant.MIN; + /** + * Constructs a new Show handler. + * + * @param version the version of the bot + * @param configuration the bot configuration + */ public Show(String version, Configuration configuration) { this.version = version; this.configuration = configuration; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { event.replyEmbeds(getResponse(event, context)).queue(); } + /** + * Generates the response embed message for the slash command. + * + * @param event the slash command interaction event + * @param context the event context + * @return the response embed message + */ @NotNull private MessageEmbed getResponse(SlashCommandInteractionEvent event, EventContext context) { if (contributors == null || lastFetch.isBefore(Instant.now().minus(5, ChronoUnit.MINUTES))) { @@ -111,6 +134,12 @@ private MessageEmbed getResponse(SlashCommandInteractionEvent event, EventContex .build(); } + /** + * Generates a string of links for the embed message. + * + * @param context the event context + * @return a string of links + */ private String getLinks(EventContext context) { var links = List.of( getLink(context, "command.info.message.inviteme", configuration.links().invite()), @@ -122,17 +151,39 @@ private String getLinks(EventContext context) { return String.join(" ᠅ ", links); } + /** + * Generates a localized link for the embed message. + * + * @param context the event context + * @param target the localization key for the link text + * @param url the URL for the link + * @return a localized link + */ private String getLink(EventContext context, @PropertyKey(resourceBundle = "locale") String target, String url) { return context.localize("words.link", Replacement.create("TARGET", String.format("$%s$", target)), Replacement.create("URL", url)); } + /** + * Generates an untranslated link for the embed message. + * + * @param context the event context + * @param target the link text + * @param url the URL for the link + * @return an untranslated link + */ private String getUntranslatedLink(EventContext context, String target, String url) { return context.localize("words.link", Replacement.create("TARGET", target), Replacement.create("URL", url)); } + /** + * Generates a string of voting links for the embed message. + * + * @param context the event context + * @return a string of voting links + */ private String getVoting(EventContext context) { List voteLinks = new ArrayList<>(); @@ -143,6 +194,9 @@ private String getVoting(EventContext context) { return String.join(" ᠅ ", voteLinks); } + /** + * Enum representing the type of contributor. + */ @SuppressWarnings("unused") private enum ContributorType { @JsonProperty("User") @@ -151,6 +205,9 @@ private enum ContributorType { BOT } + /** + * Represents a contributor to the GitHub repository. + */ @SuppressWarnings("unused") private static class Contributor { private String login; @@ -160,6 +217,9 @@ private static class Contributor { private ContributorType type; } + /** + * Represents a GitHub profile. + */ @SuppressWarnings("unused") private static class GithubProfile { private String login; diff --git a/src/main/java/de/chojo/repbot/commands/invite/Invite.java b/src/main/java/de/chojo/repbot/commands/invite/Invite.java index 5cab6ae89..42ea39b97 100644 --- a/src/main/java/de/chojo/repbot/commands/invite/Invite.java +++ b/src/main/java/de/chojo/repbot/commands/invite/Invite.java @@ -10,7 +10,16 @@ import de.chojo.repbot.commands.invite.handler.Show; import de.chojo.repbot.config.Configuration; +/** + * Command class for the invite command. + */ public class Invite extends SlashCommand { + + /** + * Constructs a new Invite command. + * + * @param configuration the configuration of the application + */ public Invite(Configuration configuration) { super(Slash.of("invite", "command.invite.description") .command(new Show(configuration))); diff --git a/src/main/java/de/chojo/repbot/commands/invite/handler/Show.java b/src/main/java/de/chojo/repbot/commands/invite/handler/Show.java index b36729c6a..69acf5faa 100644 --- a/src/main/java/de/chojo/repbot/commands/invite/handler/Show.java +++ b/src/main/java/de/chojo/repbot/commands/invite/handler/Show.java @@ -14,18 +14,39 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import org.jetbrains.annotations.NotNull; +/** + * Handler for the "show invite" slash command. + * This command displays an invite link for the bot. + */ public class Show implements SlashHandler { private final Configuration configuration; + /** + * Constructs a new Show handler. + * + * @param configuration the bot configuration + */ public Show(Configuration configuration) { this.configuration = configuration; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { event.replyEmbeds(getResponse(context)).queue(); } + /** + * Generates the response embed message for the slash command. + * + * @param context the event context + * @return the response embed message + */ @NotNull private MessageEmbed getResponse(EventContext context) { return new LocalizedEmbedBuilder(context.guildLocalizer()) diff --git a/src/main/java/de/chojo/repbot/commands/locale/Locale.java b/src/main/java/de/chojo/repbot/commands/locale/Locale.java index 6888269d8..e90899907 100644 --- a/src/main/java/de/chojo/repbot/commands/locale/Locale.java +++ b/src/main/java/de/chojo/repbot/commands/locale/Locale.java @@ -14,7 +14,15 @@ import de.chojo.repbot.commands.locale.handler.Set; import de.chojo.repbot.dao.provider.Guilds; +/** + * Command for managing locale settings. + */ public class Locale extends SlashCommand { + /** + * Constructs a new Locale command with the specified Guilds provider. + * + * @param guilds the Guilds provider + */ public Locale(Guilds guilds) { super(Slash.of("locale", "command.locale.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/locale/handler/List.java b/src/main/java/de/chojo/repbot/commands/locale/handler/List.java index 74df1c0f6..9f36da81e 100644 --- a/src/main/java/de/chojo/repbot/commands/locale/handler/List.java +++ b/src/main/java/de/chojo/repbot/commands/locale/handler/List.java @@ -10,7 +10,23 @@ import de.chojo.jdautil.wrapper.EventContext; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the list locales command. + */ public class List implements SlashHandler { + + /** + * Creates a new list handler. + */ + public List(){ + } + + /** + * Handles the slash command interaction event to list available locales. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var languages = context.guildLocalizer().localizer().languages(); diff --git a/src/main/java/de/chojo/repbot/commands/locale/handler/Reset.java b/src/main/java/de/chojo/repbot/commands/locale/handler/Reset.java index b674af6ea..2b32cd310 100644 --- a/src/main/java/de/chojo/repbot/commands/locale/handler/Reset.java +++ b/src/main/java/de/chojo/repbot/commands/locale/handler/Reset.java @@ -10,13 +10,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the reset locale command. + */ public class Reset implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Reset handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Reset(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to reset the locale. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { guilds.guild(event.getGuild()).settings().general().language(null); diff --git a/src/main/java/de/chojo/repbot/commands/locale/handler/Set.java b/src/main/java/de/chojo/repbot/commands/locale/handler/Set.java index 0195568ef..7f2a30051 100644 --- a/src/main/java/de/chojo/repbot/commands/locale/handler/Set.java +++ b/src/main/java/de/chojo/repbot/commands/locale/handler/Set.java @@ -15,13 +15,27 @@ import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.DiscordLocale; +/** + * Handler for setting the locale of a guild. + */ public class Set implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Set handler. + * + * @param guilds the guilds provider + */ public Set(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command to set the locale. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { DiscordLocale locale = null; @@ -42,6 +56,12 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont } } + /** + * Handles the auto-complete interaction for the locale command. + * + * @param event the command auto-complete interaction event + * @param context the event context + */ @Override public void onAutoComplete(CommandAutoCompleteInteractionEvent event, EventContext context) { var option = event.getFocusedOption(); diff --git a/src/main/java/de/chojo/repbot/commands/log/Log.java b/src/main/java/de/chojo/repbot/commands/log/Log.java index 75df3d547..0b0a11147 100644 --- a/src/main/java/de/chojo/repbot/commands/log/Log.java +++ b/src/main/java/de/chojo/repbot/commands/log/Log.java @@ -16,7 +16,15 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.Permission; +/** + * Command for managing log-related actions. + */ public class Log extends SlashCommand { + /** + * Constructs a new Log command with the specified Guilds provider. + * + * @param guilds the Guilds provider + */ public Log(Guilds guilds) { super(Slash.of("log", "command.log.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/log/handler/Analyzer.java b/src/main/java/de/chojo/repbot/commands/log/handler/Analyzer.java index 6f0d4cd84..73429c1fa 100644 --- a/src/main/java/de/chojo/repbot/commands/log/handler/Analyzer.java +++ b/src/main/java/de/chojo/repbot/commands/log/handler/Analyzer.java @@ -8,25 +8,45 @@ import de.chojo.jdautil.interactions.slash.structure.handler.SlashHandler; import de.chojo.jdautil.localization.util.LocalizedEmbedBuilder; import de.chojo.jdautil.localization.util.Replacement; -import de.chojo.jdautil.parsing.ValueParser; import de.chojo.jdautil.wrapper.EventContext; import de.chojo.repbot.dao.provider.Guilds; -import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; +/** + * Handler for the "analyzer" slash command. + */ public class Analyzer extends BaseAnalyzer implements SlashHandler { private final Guilds guilds; + /** + * Constructs an Analyzer handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Analyzer(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { onSlashCommand(event, context, guilds.guild(event.getGuild()).reputation()); } + /** + * Sends the analyzer log for the specified message ID. + * + * @param callback the reply callback + * @param guilds the guilds provider + * @param messageId the ID of the message to analyze + * @param context the event context + */ public static void sendAnalyzerLog(IReplyCallback callback, Guilds guilds, long messageId, EventContext context) { var reputation = guilds.guild(callback.getGuild()).reputation(); var resultEntry = reputation.analyzer() diff --git a/src/main/java/de/chojo/repbot/commands/log/handler/BaseAnalyzer.java b/src/main/java/de/chojo/repbot/commands/log/handler/BaseAnalyzer.java index f9f3709ef..9a1ea0cf3 100644 --- a/src/main/java/de/chojo/repbot/commands/log/handler/BaseAnalyzer.java +++ b/src/main/java/de/chojo/repbot/commands/log/handler/BaseAnalyzer.java @@ -12,7 +12,24 @@ import de.chojo.repbot.dao.access.guild.reputation.Reputation; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the slash command for analyzing reputation logs. + */ public class BaseAnalyzer { + + /** + * Creates a new base analyzer. + */ + public BaseAnalyzer(){ + } + + /** + * Handles the slash command interaction event to analyze reputation logs. + * + * @param event the slash command interaction event + * @param context the event context + * @param reputation the reputation access object + */ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context, Reputation reputation) { var optMessageId = ValueParser.parseLong(event.getOption("messageid").getAsString()); if (optMessageId.isEmpty()) { @@ -42,6 +59,5 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont embed.add(builder.build()); event.replyEmbeds(embed).setEphemeral(true).queue(); - } } diff --git a/src/main/java/de/chojo/repbot/commands/log/handler/Donated.java b/src/main/java/de/chojo/repbot/commands/log/handler/Donated.java index fac747eee..9bc21059d 100644 --- a/src/main/java/de/chojo/repbot/commands/log/handler/Donated.java +++ b/src/main/java/de/chojo/repbot/commands/log/handler/Donated.java @@ -11,7 +11,6 @@ import de.chojo.repbot.dao.provider.Guilds; import de.chojo.repbot.dao.snapshots.ReputationLogEntry; import net.dv8tion.jda.api.entities.Member; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.interactions.callbacks.IReplyCallback; import net.dv8tion.jda.api.utils.messages.MessageEditData; @@ -23,19 +22,41 @@ import static de.chojo.repbot.commands.log.handler.LogFormatter.mapUserLogEntry; import static de.chojo.repbot.commands.log.handler.LogFormatter.userLogEmbed; +/** + * Handles the slash command for displaying donated reputation logs. + */ public class Donated implements SlashHandler { private final Guilds guilds; + /** + * Constructs a Donated handler with the specified guild provider. + * + * @param guilds the guild provider + */ public Donated(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to display donated reputation logs. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var user = event.getOption("user").getAsMember(); send(event, user, guilds, context); } + /** + * Sends the donated reputation logs to the user. + * + * @param event the reply callback event + * @param user the member whose logs are to be displayed + * @param guilds the guild provider + * @param context the event context + */ public static void send(IReplyCallback event, Member user, Guilds guilds, EventContext context) { var logAccess = guilds.guild(event.getGuild()).reputation().log().userDonatedLog(user.getUser(), PAGE_SIZE); context.registerPage(new PrivatePageBag(logAccess.pages(), event.getUser().getIdLong()) { diff --git a/src/main/java/de/chojo/repbot/commands/log/handler/LogFormatter.java b/src/main/java/de/chojo/repbot/commands/log/handler/LogFormatter.java index db5ef09da..cc1fc8cf7 100644 --- a/src/main/java/de/chojo/repbot/commands/log/handler/LogFormatter.java +++ b/src/main/java/de/chojo/repbot/commands/log/handler/LogFormatter.java @@ -20,13 +20,28 @@ import java.util.StringJoiner; import java.util.function.Function; +/** + * Utility class for formatting log entries. + */ public final class LogFormatter { static final int PAGE_SIZE = 15; + /** + * Private constructor to prevent instantiation. + * Throws an UnsupportedOperationException if called. + */ private LogFormatter() { throw new UnsupportedOperationException("This is a utility class."); } + /** + * Maps a list of ReputationLogEntry to a list of formatted log entry strings for a user. + * + * @param context the EventContext for localization + * @param logEntries the list of ReputationLogEntry to map + * @param userId a function to extract the user ID from a ReputationLogEntry + * @return a list of formatted log entry strings + */ static List mapUserLogEntry(EventContext context, List logEntries, Function userId) { List entries = new ArrayList<>(); for (var logEntry : logEntries) { @@ -38,6 +53,13 @@ static List mapUserLogEntry(EventContext context, List mapMessageLogEntry(EventContext context, List logEntries) { if (logEntries.isEmpty()) return Collections.emptyList(); @@ -52,6 +74,13 @@ public static List mapMessageLogEntry(EventContext context, List log) { var builder = new LocalizedEmbedBuilder(context.guildLocalizer()) .setAuthor(title, null, user.getEffectiveAvatarUrl(), Replacement.create("USER", user.getEffectiveName())); @@ -74,6 +112,12 @@ static MessageEditData userLogEmbed(EventContext context, Member user, String ti return MessageEditData.fromEmbeds(builder.build()); } + /** + * Builds the fields of an embed with the given log entries. + * + * @param entries the list of log entry strings + * @param embedBuilder the LocalizedEmbedBuilder to build the fields on + */ public static void buildFields(List entries, LocalizedEmbedBuilder embedBuilder) { var joiner = new StringJoiner("\n"); for (var entry : entries) { diff --git a/src/main/java/de/chojo/repbot/commands/log/handler/Message.java b/src/main/java/de/chojo/repbot/commands/log/handler/Message.java index b89ac49cc..f94c97b15 100644 --- a/src/main/java/de/chojo/repbot/commands/log/handler/Message.java +++ b/src/main/java/de/chojo/repbot/commands/log/handler/Message.java @@ -18,13 +18,27 @@ import static de.chojo.repbot.commands.log.handler.LogFormatter.buildFields; import static de.chojo.repbot.commands.log.handler.LogFormatter.mapMessageLogEntry; +/** + * Handler for the message log command. + */ public class Message implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Message handler with the specified Guilds provider. + * + * @param guilds the Guilds provider + */ public Message(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for logging a message. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { event.getOption("messageid"); @@ -38,6 +52,14 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont .setEphemeral(true).queue(); } + /** + * Retrieves the message log and constructs a MessageEmbed. + * + * @param context the EventContext + * @param guild the Guild + * @param messageId the ID of the message + * @return the constructed MessageEmbed + */ private MessageEmbed getMessageLog(EventContext context, Guild guild, long messageId) { var messageLog = guilds.guild(guild).reputation().log().messageLog(messageId, 50); diff --git a/src/main/java/de/chojo/repbot/commands/log/handler/Received.java b/src/main/java/de/chojo/repbot/commands/log/handler/Received.java index 63c367507..f34f3ad36 100644 --- a/src/main/java/de/chojo/repbot/commands/log/handler/Received.java +++ b/src/main/java/de/chojo/repbot/commands/log/handler/Received.java @@ -24,19 +24,41 @@ import static de.chojo.repbot.commands.log.handler.LogFormatter.mapUserLogEntry; import static de.chojo.repbot.commands.log.handler.LogFormatter.userLogEmbed; +/** + * Handles the received reputation log command. + */ public class Received implements SlashHandler { private final Guilds guilds; + /** + * Constructs a Received handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Received(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var user = event.getOption("user").getAsMember(); - send(event,user, guilds, context); + send(event, user, guilds, context); } + /** + * Sends the received reputation log to the user. + * + * @param callback the reply callback + * @param user the member whose log is being retrieved + * @param guilds the guilds provider + * @param context the event context + */ public static void send(IReplyCallback callback, Member user, Guilds guilds, EventContext context) { var logAccess = guilds.guild(callback.getGuild()).reputation().log().getUserReceivedLog(user.getUser(), PAGE_SIZE); context.registerPage(new PrivatePageBag(logAccess.pages(), callback.getUser().getIdLong()) { diff --git a/src/main/java/de/chojo/repbot/commands/messages/Messages.java b/src/main/java/de/chojo/repbot/commands/messages/Messages.java index 707651c81..c9773eb39 100644 --- a/src/main/java/de/chojo/repbot/commands/messages/Messages.java +++ b/src/main/java/de/chojo/repbot/commands/messages/Messages.java @@ -11,7 +11,15 @@ import de.chojo.repbot.commands.messages.handler.States; import de.chojo.repbot.dao.provider.Guilds; +/** + * Represents the messages command for the bot. + */ public class Messages extends SlashCommand { + /** + * Constructs a Messages command with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Messages(Guilds guilds) { super(Slash.of("messages", "command.messages.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/messages/handler/States.java b/src/main/java/de/chojo/repbot/commands/messages/handler/States.java index 867c9facc..77d869953 100644 --- a/src/main/java/de/chojo/repbot/commands/messages/handler/States.java +++ b/src/main/java/de/chojo/repbot/commands/messages/handler/States.java @@ -22,13 +22,28 @@ import java.util.Collections; import java.util.function.Consumer; +/** + * Handler for the "states" slash command. + * This command manages the state settings for messages in the guild. + */ public class States implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new States handler. + * + * @param guilds the guilds provider + */ public States(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var settings = guilds.guild(event.getGuild()).settings(); @@ -62,6 +77,16 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont .build()); } + /** + * Creates a StringSelectMenu for the given parameters. + * + * @param id the menu ID + * @param placeholder the placeholder text + * @param enabledDescr the description for the enabled state + * @param disabledDescr the description for the disabled state + * @param state the current state + * @return the created StringSelectMenu + */ private StringSelectMenu getMenu(String id, String placeholder, String enabledDescr, String disabledDescr, boolean state) { return StringSelectMenu.create(id) .setPlaceholder(placeholder) @@ -72,6 +97,14 @@ private StringSelectMenu getMenu(String id, String placeholder, String enabledDe .build(); } + /** + * Refreshes the menu entry context with the new state. + * + * @param ctx the entry context + * @param result the result consumer + * @param context the event context + * @param guildSettings the guild settings + */ private void refresh(EntryContext ctx, Consumer result, EventContext context, Settings guildSettings) { var value = ctx.event().getValues().get(0); var copy = ctx.entry().component().createCopy(); @@ -82,6 +115,13 @@ private void refresh(EntryContext\\d*?)>"); private final Guilds guilds; + /** + * Constructs a Remove handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Remove(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for removing reactions. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var reactions = guilds.guild(event.getGuild()).settings().thanking().reactions(); @@ -44,6 +58,12 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont event.reply(context.localize("command.reactions.remove.message.notfound")).setEphemeral(true).queue(); } + /** + * Handles the auto-complete interaction event for the emote option. + * + * @param event the auto-complete interaction event + * @param context the event context + */ @Override public void onAutoComplete(CommandAutoCompleteInteractionEvent event, EventContext context) { if ("emote".equals(event.getFocusedOption().getName())) { diff --git a/src/main/java/de/chojo/repbot/commands/reactions/util/CheckResult.java b/src/main/java/de/chojo/repbot/commands/reactions/util/CheckResult.java index 0efa62a7f..5dba0c1d9 100644 --- a/src/main/java/de/chojo/repbot/commands/reactions/util/CheckResult.java +++ b/src/main/java/de/chojo/repbot/commands/reactions/util/CheckResult.java @@ -5,6 +5,27 @@ */ package de.chojo.repbot.commands.reactions.util; +/** + * Enum representing the result of a check for reactions. + */ public enum CheckResult { - EMOJI_FOUND, EMOTE_FOUND, NOT_FOUND, UNKNOWN_EMOJI + /** + * Indicates that an emoji was found. + */ + EMOJI_FOUND, + + /** + * Indicates that an emote was found. + */ + EMOTE_FOUND, + + /** + * Indicates that nothing was found. + */ + NOT_FOUND, + + /** + * Indicates that an unknown emoji was found. + */ + UNKNOWN_EMOJI } diff --git a/src/main/java/de/chojo/repbot/commands/reactions/util/EmojiCheck.java b/src/main/java/de/chojo/repbot/commands/reactions/util/EmojiCheck.java index 806c98b91..d2c362cc4 100644 --- a/src/main/java/de/chojo/repbot/commands/reactions/util/EmojiCheck.java +++ b/src/main/java/de/chojo/repbot/commands/reactions/util/EmojiCheck.java @@ -11,11 +11,24 @@ import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji; import net.dv8tion.jda.api.exceptions.ErrorResponseException; +/** + * Utility class for checking and validating emojis in messages. + */ public final class EmojiCheck { + /** + * Private constructor to prevent instantiation. + */ private EmojiCheck() { throw new UnsupportedOperationException("This is a utility class."); } + /** + * Checks the provided emoji in the context of the given message. + * + * @param message the message containing the emoji + * @param emote the emoji to check + * @return the result of the emoji check + */ public static EmojiCheckResult checkEmoji(Message message, String emote) { // Check for emote id if (Verifier.isValidId(emote)) { @@ -42,16 +55,22 @@ public static EmojiCheckResult checkEmoji(Message message, String emote) { .getId(), CheckResult.EMOTE_FOUND); } - // check for unicode + // Check for unicode try { message.addReaction(Emoji.fromUnicode(emote)).complete(); } catch (ErrorResponseException e) { - return new EmojiCheckResult(null, "", CheckResult.UNKNOWN_EMOJI); } return new EmojiCheckResult(emote, "", CheckResult.EMOJI_FOUND); } + /** + * Checks if the given custom emoji can be used in the context of the provided message. + * + * @param emote the custom emoji to check + * @param message the message containing the emoji + * @return true if the emoji can be used, false otherwise + */ private static boolean canUse(RichCustomEmoji emote, Message message) { if (emote == null) { return false; @@ -63,5 +82,4 @@ private static boolean canUse(RichCustomEmoji emote, Message message) { } return true; } - } diff --git a/src/main/java/de/chojo/repbot/commands/reactions/util/EmojiCheckResult.java b/src/main/java/de/chojo/repbot/commands/reactions/util/EmojiCheckResult.java index e087016ed..e80285f73 100644 --- a/src/main/java/de/chojo/repbot/commands/reactions/util/EmojiCheckResult.java +++ b/src/main/java/de/chojo/repbot/commands/reactions/util/EmojiCheckResult.java @@ -5,5 +5,12 @@ */ package de.chojo.repbot.commands.reactions.util; +/** + * Represents the result of an emoji check. + * + * @param mention the mention string + * @param id the ID of the emoji + * @param result the result of the check + */ public record EmojiCheckResult(String mention, String id, CheckResult result) { } diff --git a/src/main/java/de/chojo/repbot/commands/repadmin/RepAdmin.java b/src/main/java/de/chojo/repbot/commands/repadmin/RepAdmin.java index 183ec9ac9..257c71e7e 100644 --- a/src/main/java/de/chojo/repbot/commands/repadmin/RepAdmin.java +++ b/src/main/java/de/chojo/repbot/commands/repadmin/RepAdmin.java @@ -23,8 +23,18 @@ import java.time.LocalDate; +/** + * Slash command for managing reputation and reset dates in the bot. + */ public class RepAdmin extends SlashCommand { + /** + * Constructs a RepAdmin command with the specified guilds provider, configuration, and role assigner. + * + * @param guilds the guilds provider + * @param configuration the configuration + * @param roleAssigner the role assigner + */ public RepAdmin(Guilds guilds, Configuration configuration, RoleAssigner roleAssigner) { super(Slash.of("repadmin", "command.repadmin.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/repadmin/handler/Profile.java b/src/main/java/de/chojo/repbot/commands/repadmin/handler/Profile.java index dba413370..24b7e9b96 100644 --- a/src/main/java/de/chojo/repbot/commands/repadmin/handler/Profile.java +++ b/src/main/java/de/chojo/repbot/commands/repadmin/handler/Profile.java @@ -11,15 +11,30 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the profile command for the reputation admin. + */ public class Profile implements SlashHandler { private final Guilds guilds; private final Configuration configuration; + /** + * Constructs a Profile handler with the specified guilds provider and configuration. + * + * @param guilds the guilds provider + * @param configuration the configuration + */ public Profile(Guilds guilds, Configuration configuration) { this.guilds = guilds; this.configuration = configuration; } + /** + * Handles the slash command interaction event for displaying a user's profile. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var user = guilds.guild(event.getGuild()).reputation().user(event.getOption("user").getAsMember()); diff --git a/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Add.java b/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Add.java index 290933183..2029f3b02 100644 --- a/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Add.java +++ b/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Add.java @@ -13,12 +13,30 @@ import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the "add reputation" slash command, which adds reputation to a user. + */ public class Add extends BaseReputationModifier { + /** + * Constructs an Add handler with the specified role assigner and guilds provider. + * + * @param roleAssigner the role assigner + * @param guilds the guilds provider + */ public Add(RoleAssigner roleAssigner, Guilds guilds) { super(roleAssigner, guilds); } + /** + * Executes the slash command interaction event to add reputation to a user. + * + * @param event the slash command interaction event + * @param context the event context + * @param user the user to add reputation to + * @param repUser the reputation user object + * @param rep the amount of reputation to add + */ @Override void execute(SlashCommandInteractionEvent event, EventContext context, User user, RepUser repUser, long rep) { repUser.addReputation(rep); diff --git a/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/BaseReputationModifier.java b/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/BaseReputationModifier.java index ab67824c3..7a98e9a07 100644 --- a/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/BaseReputationModifier.java +++ b/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/BaseReputationModifier.java @@ -14,16 +14,31 @@ import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Abstract base class for handling reputation modification commands. + */ public abstract class BaseReputationModifier implements SlashHandler { private final RoleAssigner roleAssigner; private final Guilds guilds; + /** + * Constructs a BaseReputationModifier with the specified role assigner and guild provider. + * + * @param roleAssigner the role assigner service + * @param guilds the guild provider + */ public BaseReputationModifier(RoleAssigner roleAssigner, Guilds guilds) { this.roleAssigner = roleAssigner; this.guilds = guilds; } + /** + * Handles the slash command interaction event for modifying reputation. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var user = event.getOption("user").getAsUser(); @@ -34,5 +49,14 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont roleAssigner.updateReporting(member, event.getChannel().asGuildMessageChannel()); } + /** + * Executes the reputation modification logic. + * + * @param event the slash command interaction event + * @param context the event context + * @param user the user whose reputation is being modified + * @param repUser the reputation user object + * @param rep the amount of reputation to modify + */ abstract void execute(SlashCommandInteractionEvent event, EventContext context, User user, RepUser repUser, long rep); } diff --git a/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Remove.java b/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Remove.java index f4b5b85bd..429df674a 100644 --- a/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Remove.java +++ b/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Remove.java @@ -13,12 +13,30 @@ import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the removal of reputation from a user. + */ public class Remove extends BaseReputationModifier { + /** + * Constructs a Remove handler with the specified role assigner and guilds provider. + * + * @param roleAssigner the role assigner + * @param guilds the guilds provider + */ public Remove(RoleAssigner roleAssigner, Guilds guilds) { super(roleAssigner, guilds); } + /** + * Executes the removal of reputation from a user. + * + * @param event the slash command interaction event + * @param context the event context + * @param user the user whose reputation is being removed + * @param repUser the reputation user object + * @param rep the amount of reputation to remove + */ @Override void execute(SlashCommandInteractionEvent event, EventContext context, User user, RepUser repUser, long rep) { repUser.removeReputation(rep); diff --git a/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Set.java b/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Set.java index 2b62d6669..6cee135b2 100644 --- a/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Set.java +++ b/src/main/java/de/chojo/repbot/commands/repadmin/handler/reputation/Set.java @@ -13,15 +13,36 @@ import net.dv8tion.jda.api.entities.User; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for setting a user's reputation. + */ public class Set extends BaseReputationModifier { + /** + * Constructs a new Set handler. + * + * @param roleAssigner the role assigner service + * @param guilds the guilds provider + */ public Set(RoleAssigner roleAssigner, Guilds guilds) { super(roleAssigner, guilds); } + /** + * Executes the command to set a user's reputation. + * + * @param event the slash command interaction event + * @param context the event context + * @param user the user whose reputation is being set + * @param repUser the reputation user object + * @param rep the reputation value to set + */ @Override void execute(SlashCommandInteractionEvent event, EventContext context, User user, RepUser repUser, long rep) { + // Set the user's reputation to the specified value repUser.setReputation(rep); + + // Reply to the event with a localized message indicating the reputation has been set event.reply(context.localize("command.repadmin.reputation.set.message.set", Replacement.create("VALUE", rep), Replacement.createMention(user))) .setEphemeral(true).queue(); diff --git a/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/CurrentResetDate.java b/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/CurrentResetDate.java index 245bf2c65..625c0194e 100644 --- a/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/CurrentResetDate.java +++ b/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/CurrentResetDate.java @@ -13,14 +13,28 @@ import java.time.format.DateTimeFormatter; +/** + * Handles the slash command for retrieving the current reset date. + */ public class CurrentResetDate implements SlashHandler { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd"); private final Guilds guilds; + /** + * Constructs a CurrentResetDate handler with the specified guild provider. + * + * @param guilds the guild provider + */ public CurrentResetDate(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to get the current reset date. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var date = guilds.guild(event.getGuild()).settings().general().resetDate(); diff --git a/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/RemoveResetDate.java b/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/RemoveResetDate.java index 4be3ff9e8..28fd33e7d 100644 --- a/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/RemoveResetDate.java +++ b/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/RemoveResetDate.java @@ -10,13 +10,27 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handles the removal of the reset date for a guild. + */ public class RemoveResetDate implements SlashHandler { private final Guilds guilds; + /** + * Constructs a RemoveResetDate handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public RemoveResetDate(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for removing the reset date. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { guilds.guild(event.getGuild()).settings().general().resetDate(null); diff --git a/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/SetResetDate.java b/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/SetResetDate.java index 18f582fb4..f9839e94f 100644 --- a/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/SetResetDate.java +++ b/src/main/java/de/chojo/repbot/commands/repadmin/handler/resetdate/SetResetDate.java @@ -15,14 +15,29 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; +/** + * Handler for the "set reset date" slash command. + * This command sets the reset date for the guild's settings. + */ public class SetResetDate implements SlashHandler { private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy.MM.dd"); private final Guilds guilds; + /** + * Constructs a new SetResetDate handler. + * + * @param guilds the guilds provider + */ public SetResetDate(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var year = event.getOption("year").getAsInt(); diff --git a/src/main/java/de/chojo/repbot/commands/repsettings/RepSettings.java b/src/main/java/de/chojo/repbot/commands/repsettings/RepSettings.java index 886096b07..791a55ef1 100644 --- a/src/main/java/de/chojo/repbot/commands/repsettings/RepSettings.java +++ b/src/main/java/de/chojo/repbot/commands/repsettings/RepSettings.java @@ -12,8 +12,16 @@ import de.chojo.repbot.commands.repsettings.handler.Info; import de.chojo.repbot.dao.provider.Guilds; +/** + * Slash command for managing reputation settings in the bot. + */ public class RepSettings extends SlashCommand { + /** + * Constructs a RepSettings command with the specified guilds provider. + * + * @param guilds the guilds provider + */ public RepSettings(Guilds guilds) { super(Slash.of("repsettings", "command.repsettings.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/repsettings/handler/EmojiInfo.java b/src/main/java/de/chojo/repbot/commands/repsettings/handler/EmojiInfo.java index 7c38df6e4..3cd28c128 100644 --- a/src/main/java/de/chojo/repbot/commands/repsettings/handler/EmojiInfo.java +++ b/src/main/java/de/chojo/repbot/commands/repsettings/handler/EmojiInfo.java @@ -24,14 +24,28 @@ import static de.chojo.repbot.util.EmojiDebug.TARGET_NOT_IN_CONTEXT; import static de.chojo.repbot.util.EmojiDebug.TOO_OLD; +/** + * Handles the emoji information slash command. + */ public class EmojiInfo implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new EmojiInfo instance. + * + * @param guilds the Guilds instance + */ public EmojiInfo(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var generalSettings = guilds.guild(event.getGuild()).settings().general(); @@ -40,6 +54,11 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont + "\n" + context.localize(emojiExplanation())).queue(); } + /** + * Provides an explanation of the emoji debug messages. + * + * @return the explanation string + */ private String emojiExplanation() { var emojis = List.of( String.format("$%s$", "command.repsettings.emojidebug.message.title"), @@ -56,6 +75,13 @@ private String emojiExplanation() { return String.join("\n", emojis); } + /** + * Formats an emoji string with its corresponding message code. + * + * @param emoji the emoji string + * @param code the message code + * @return the formatted emoji string + */ private String emojiString(String emoji, @PropertyKey(resourceBundle = "locale") String code) { return String.format("%s ➜ $%s$", emoji, code); } diff --git a/src/main/java/de/chojo/repbot/commands/repsettings/handler/Info.java b/src/main/java/de/chojo/repbot/commands/repsettings/handler/Info.java index 7c0477dfe..651110bc6 100644 --- a/src/main/java/de/chojo/repbot/commands/repsettings/handler/Info.java +++ b/src/main/java/de/chojo/repbot/commands/repsettings/handler/Info.java @@ -23,13 +23,27 @@ import java.util.Collections; import java.util.function.Consumer; +/** + * Handler for the reputation settings info command. + */ public class Info implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Info handler. + * + * @param guilds the Guilds provider + */ public Info(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guildSettings = guilds.guild(event.getGuild()).settings(); @@ -138,6 +152,16 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont .build()); } + /** + * Creates a StringSelectMenu for the given parameters. + * + * @param id the ID of the menu + * @param placeholder the placeholder text for the menu + * @param enabledDescr the description for the enabled state + * @param disabledDescr the description for the disabled state + * @param state the current state + * @return the created StringSelectMenu + */ private StringSelectMenu getMenu(String id, String placeholder, String enabledDescr, String disabledDescr, boolean state) { return StringSelectMenu.create(id) .setPlaceholder(placeholder) @@ -148,6 +172,14 @@ private StringSelectMenu getMenu(String id, String placeholder, String enabledDe .build(); } + /** + * Refreshes the menu entry with the given context and result consumer. + * + * @param ctx the EntryContext + * @param result the result consumer + * @param context the EventContext + * @param guildSettings the guild settings + */ private void refresh(EntryContext ctx, Consumer result, EventContext context, Settings guildSettings) { var value = ctx.event().getValues().get(0); @@ -159,6 +191,13 @@ private void refresh(EntryContext { private final Refresh refresh; private final Guilds guilds; + /** + * Constructs a new Roles instance. + * + * @param guilds the guilds provider + * @param roleAssigner the role assigner service + */ public Roles(Guilds guilds, RoleAssigner roleAssigner) { this.guilds = guilds; - refresh = new Refresh(roleAssigner); + this.refresh = new Refresh(roleAssigner); } + /** + * Defines the slash commands for roles. + * + * @return the slash command definition + */ @Override public Slash slash() { return Slash.of("roles", "command.roles.description") @@ -76,6 +90,12 @@ public Slash slash() { ).build(); } + /** + * Checks if the refresh process is active for the specified guild. + * + * @param guild the guild to check + * @return true if the refresh process is active, false otherwise + */ public boolean refreshActive(Guild guild) { return refresh.refreshActive(guild); } diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/Add.java b/src/main/java/de/chojo/repbot/commands/roles/handler/Add.java index eb99da233..ed082cb60 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/Add.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/Add.java @@ -14,12 +14,28 @@ import java.util.function.Consumer; +/** + * Handler for the "add role" slash command, which adds a role with a specified reputation. + */ public class Add extends BaseRoleModifier { + /** + * Constructs an Add handler with the specified refresh function and guilds provider. + * + * @param refresh the refresh function + * @param guilds the guilds provider + */ public Add(Refresh refresh, Guilds guilds) { super(refresh, guilds); } + /** + * Modifies the roles by adding a new role with the specified reputation. + * + * @param event the slash command interaction event + * @param context the event context + * @param refresh the consumer to refresh the message embed + */ @Override public void modify(SlashCommandInteractionEvent event, EventContext context, Consumer refresh) { var role = event.getOption("role").getAsRole(); diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/BaseRoleModifier.java b/src/main/java/de/chojo/repbot/commands/roles/handler/BaseRoleModifier.java index f067b4867..0fb80ba0a 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/BaseRoleModifier.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/BaseRoleModifier.java @@ -17,16 +17,31 @@ import java.util.function.Consumer; +/** + * Abstract base class for handling role modification commands. + */ public abstract class BaseRoleModifier implements SlashHandler { private final Refresh refresh; private final Guilds guilds; + /** + * Constructs a BaseRoleModifier with the specified refresh handler and guilds provider. + * + * @param refresh the refresh handler + * @param guilds the guilds provider + */ public BaseRoleModifier(Refresh refresh, Guilds guilds) { this.refresh = refresh; this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { Consumer refreshConsumer = menu -> { @@ -37,8 +52,20 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont modify(event, context, refreshConsumer); } + /** + * Abstract method to modify roles, to be implemented by subclasses. + * + * @param event the slash command interaction event + * @param context the event context + * @param refresh the consumer to handle refresh actions + */ public abstract void modify(SlashCommandInteractionEvent event, EventContext context, Consumer refresh); + /** + * Gets the guilds provider. + * + * @return the guilds provider + */ public Guilds guilds() { return guilds; } diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/List.java b/src/main/java/de/chojo/repbot/commands/roles/handler/List.java index ad6539abb..26b763833 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/List.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/List.java @@ -18,18 +18,39 @@ import java.util.Comparator; import java.util.stream.Collectors; +/** + * Handler for the list roles command. + */ public class List implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new List handler with the specified Guilds provider. + * + * @param guilds the Guilds provider + */ public List(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to list roles. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { event.replyEmbeds(getRoleList(context, event.getGuild())).setAllowedMentions(Collections.emptyList()).queue(); } + /** + * Generates a MessageEmbed containing the list of roles for the specified guild. + * + * @param context the EventContext for localization + * @param guild the Guild to get the role list from + * @return a MessageEmbed containing the role list + */ private MessageEmbed getRoleList(EventContext context, Guild guild) { var settings = guilds.guild(guild).settings(); var ranks = settings.ranks(); diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/Refresh.java b/src/main/java/de/chojo/repbot/commands/roles/handler/Refresh.java index ace6295c6..614ed8839 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/Refresh.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/Refresh.java @@ -28,20 +28,41 @@ import static de.chojo.repbot.util.Guilds.prettyName; import static org.slf4j.LoggerFactory.getLogger; +/** + * Handles the refresh command for updating roles in a guild. + */ public class Refresh implements SlashHandler { private static final Logger log = getLogger(Refresh.class); private final RoleAssigner roleAssigner; private final Set running = new HashSet<>(); + /** + * Constructs a Refresh handler with the specified role assigner. + * + * @param roleAssigner the role assigner service + */ public Refresh(RoleAssigner roleAssigner) { this.roleAssigner = roleAssigner; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { refresh(context, event.getGuild(), event); } + /** + * Refreshes the roles in the specified guild. + * + * @param context the event context + * @param guild the guild to refresh roles in + * @param replyCallback the reply callback + */ public void refresh(EventContext context, Guild guild, IReplyCallback replyCallback) { if (!replyCallback.isAcknowledged()) { replyCallback.deferReply().queue(); @@ -76,6 +97,12 @@ public void refresh(EventContext context, Guild guild, IReplyCallback replyCallb })); } + /** + * Checks if a refresh is currently active for the specified guild. + * + * @param guild the guild to check + * @return true if a refresh is active, false otherwise + */ public boolean refreshActive(Guild guild) { return running.contains(guild.getIdLong()); } diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/Remove.java b/src/main/java/de/chojo/repbot/commands/roles/handler/Remove.java index 764f7f837..6fc87946c 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/Remove.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/Remove.java @@ -15,12 +15,28 @@ import java.util.function.Consumer; +/** + * Handles the removal of roles from a guild's settings. + */ public class Remove extends BaseRoleModifier { + /** + * Constructs a Remove handler with the specified refresh function and guilds provider. + * + * @param refresh the refresh function + * @param guilds the guilds provider + */ public Remove(Refresh refresh, Guilds guilds) { super(refresh, guilds); } + /** + * Modifies the guild's settings by removing a role. + * + * @param event the slash command interaction event + * @param context the event context + * @param refresh the consumer to refresh the message embed + */ @Override public void modify(SlashCommandInteractionEvent event, EventContext context, Consumer refresh) { var ranks = guilds().guild(event.getGuild()).settings().ranks(); diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/StackRoles.java b/src/main/java/de/chojo/repbot/commands/roles/handler/StackRoles.java index 035425db1..67f04effa 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/StackRoles.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/StackRoles.java @@ -14,12 +14,29 @@ import java.util.function.Consumer; +/** + * Handler for the "stack roles" slash command. + * This command toggles the stacking of roles for the guild. + */ public class StackRoles extends BaseRoleModifier { + /** + * Constructs a new StackRoles handler. + * + * @param refresh the refresh consumer + * @param guilds the guilds provider + */ public StackRoles(Refresh refresh, Guilds guilds) { super(refresh, guilds); } + /** + * Modifies the stack roles setting for the guild. + * + * @param event the slash command interaction event + * @param context the event context + * @param refresh the refresh consumer + */ @Override public void modify(SlashCommandInteractionEvent event, EventContext context, Consumer refresh) { var settings = guilds().guild(event.getGuild()).settings(); diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/donor/AddDonor.java b/src/main/java/de/chojo/repbot/commands/roles/handler/donor/AddDonor.java index 999836293..4e6df4ae4 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/donor/AddDonor.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/donor/AddDonor.java @@ -13,13 +13,27 @@ import java.util.Collections; +/** + * Handler for the "add donor" slash command, which adds a role as a donor for thankwords. + */ public class AddDonor implements SlashHandler { private final Guilds guilds; + /** + * Constructs an AddDonor handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public AddDonor(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var role = event.getOption("role").getAsRole(); diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/donor/RemoveDonor.java b/src/main/java/de/chojo/repbot/commands/roles/handler/donor/RemoveDonor.java index 7e3b79923..b943b0da0 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/donor/RemoveDonor.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/donor/RemoveDonor.java @@ -13,13 +13,27 @@ import java.util.Collections; +/** + * Handles the removal of a donor role from a guild. + */ public class RemoveDonor implements SlashHandler { private final Guilds guilds; + /** + * Constructs a RemoveDonor handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public RemoveDonor(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for removing a donor role. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var role = event.getOption("role").getAsRole(); diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/receiver/AddReceiver.java b/src/main/java/de/chojo/repbot/commands/roles/handler/receiver/AddReceiver.java index af66499c3..77ad8f7ab 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/receiver/AddReceiver.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/receiver/AddReceiver.java @@ -13,13 +13,27 @@ import java.util.Collections; +/** + * Handler for the "add receiver" slash command, which adds a role as a receiver for thankwords. + */ public class AddReceiver implements SlashHandler { private final Guilds guilds; + /** + * Constructs an AddReceiver handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public AddReceiver(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var role = event.getOption("role").getAsRole(); diff --git a/src/main/java/de/chojo/repbot/commands/roles/handler/receiver/RemoveReceiver.java b/src/main/java/de/chojo/repbot/commands/roles/handler/receiver/RemoveReceiver.java index da21e3f6c..03f6284a4 100644 --- a/src/main/java/de/chojo/repbot/commands/roles/handler/receiver/RemoveReceiver.java +++ b/src/main/java/de/chojo/repbot/commands/roles/handler/receiver/RemoveReceiver.java @@ -13,13 +13,27 @@ import java.util.Collections; +/** + * Handles the removal of a receiver role from a guild. + */ public class RemoveReceiver implements SlashHandler { private final Guilds guilds; + /** + * Constructs a RemoveReceiver handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public RemoveReceiver(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for removing a receiver role. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var role = event.getOption("role").getAsRole(); diff --git a/src/main/java/de/chojo/repbot/commands/scan/Scan.java b/src/main/java/de/chojo/repbot/commands/scan/Scan.java index d57eae369..db1be8c0a 100644 --- a/src/main/java/de/chojo/repbot/commands/scan/Scan.java +++ b/src/main/java/de/chojo/repbot/commands/scan/Scan.java @@ -17,14 +17,28 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.entities.Guild; +/** + * Class representing the scan command for the bot. + */ public class Scan implements SlashProvider { private final Scanner scanner; + /** + * Constructs a new Scan command. + * + * @param guilds the guilds provider + * @param configuration the bot configuration + */ public Scan(Guilds guilds, Configuration configuration) { scanner = new Scanner(guilds, configuration); } + /** + * Defines the slash command for scanning. + * + * @return the slash command + */ @Override public Slash slash() { return Slash.of("scan", "command.scan.description") @@ -41,10 +55,21 @@ public Slash slash() { .build(); } + /** + * Initializes the scanner with the message analyzer. + * + * @param messageAnalyzer the message analyzer + */ public void lateInit(MessageAnalyzer messageAnalyzer) { scanner.lateInit(messageAnalyzer); } + /** + * Checks if the scanner is running for the given guild. + * + * @param guild the guild to check + * @return true if the scanner is running, false otherwise + */ public boolean isRunning(Guild guild) { return scanner.isRunning(guild); } diff --git a/src/main/java/de/chojo/repbot/commands/scan/handler/Cancel.java b/src/main/java/de/chojo/repbot/commands/scan/handler/Cancel.java index c31d22d43..65c3e6780 100644 --- a/src/main/java/de/chojo/repbot/commands/scan/handler/Cancel.java +++ b/src/main/java/de/chojo/repbot/commands/scan/handler/Cancel.java @@ -10,13 +10,27 @@ import de.chojo.repbot.commands.scan.util.Scanner; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the cancel scan command. + */ public class Cancel implements SlashHandler { private final Scanner scanner; + /** + * Constructs a Cancel handler with the specified scanner. + * + * @param scanner the scanner to use for canceling scans + */ public Cancel(Scanner scanner) { this.scanner = scanner; } + /** + * Handles the slash command interaction event to cancel an active scan. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { if (!scanner.isActive(event.getGuild())) { diff --git a/src/main/java/de/chojo/repbot/commands/scan/handler/Start.java b/src/main/java/de/chojo/repbot/commands/scan/handler/Start.java index d26778a17..cbf7ccbb0 100644 --- a/src/main/java/de/chojo/repbot/commands/scan/handler/Start.java +++ b/src/main/java/de/chojo/repbot/commands/scan/handler/Start.java @@ -14,13 +14,28 @@ import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the "start scan" slash command. + * This command initiates a scan process in a specified text channel. + */ public class Start implements SlashHandler { private final Scanner scanner; + /** + * Constructs a new Start handler. + * + * @param scanner the scanner utility + */ public Start(Scanner scanner) { this.scanner = scanner; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { if (!event.getGuild().getSelfMember().hasPermission(Permission.MESSAGE_HISTORY)) { diff --git a/src/main/java/de/chojo/repbot/commands/scan/util/ScanProcess.java b/src/main/java/de/chojo/repbot/commands/scan/util/ScanProcess.java index e15f8c1e3..520857764 100644 --- a/src/main/java/de/chojo/repbot/commands/scan/util/ScanProcess.java +++ b/src/main/java/de/chojo/repbot/commands/scan/util/ScanProcess.java @@ -25,7 +25,13 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Class representing a scan process for messages in a channel. + */ public class ScanProcess { + /** + * The maximum number of messages to scan. + */ public static final int MAX_MESSAGES = 10000; private static final Logger log = getLogger(ScanProcess.class); private final MessageAnalyzer messageAnalyzer; @@ -37,7 +43,6 @@ public class ScanProcess { private final Pattern pattern; private final int calls; private final Guilds guilds; - // This is the offset of two bot messages of the reputation bot. private int scanned = -2; private int hits; private int callsLeft; @@ -45,6 +50,17 @@ public class ScanProcess { private Instant lastSeen; private Thread currWorker; + /** + * Constructs a new ScanProcess. + * + * @param messageAnalyzer the message analyzer + * @param localizer the localization context + * @param progressMessage the progress message + * @param history the message history + * @param pattern the pattern to match + * @param calls the number of calls to make + * @param data the guilds provider + */ ScanProcess(MessageAnalyzer messageAnalyzer, LocalizationContext localizer, Message progressMessage, MessageHistory history, Pattern pattern, int calls, Guilds data) { this.messageAnalyzer = messageAnalyzer; loc = localizer; @@ -53,20 +69,30 @@ public class ScanProcess { this.progressMessage = progressMessage; this.history = history; this.pattern = pattern; - // The history will already contain two messages of the bot at this point. this.calls = Math.min(Math.max(0, calls + 2), MAX_MESSAGES); callsLeft = this.calls; guilds = data; } + /** + * Increments the scanned message count. + */ public void countScan() { scanned++; } + /** + * Increments the hit count. + */ public void hit() { hits++; } + /** + * Executes the scan process. + * + * @return true if there are more messages to scan, false otherwise + */ public boolean scan() { if (currWorker != null) { log.debug("Scanning takes too long. Skipping execution of scan to catch up"); @@ -136,40 +162,85 @@ public boolean scan() { return callsLeft > 0; } + /** + * Interrupts the current scan process. + * + * @return true if the scan process was interrupted, false otherwise + */ public boolean interrupt() { if (currWorker == null) return false; currWorker.interrupt(); return true; } + /** + * Retrieves the time taken for the scan. + * + * @return the time taken for the scan + */ public long getTime() { return time; } + /** + * Retrieves the guild associated with the scan. + * + * @return the guild + */ public Guild guild() { return guild; } + /** + * Retrieves the progress message. + * + * @return the progress message + */ public Message progressMessage() { return progressMessage; } + /** + * Retrieves the number of scanned messages. + * + * @return the number of scanned messages + */ public int scanned() { return scanned; } + /** + * Retrieves the number of hits. + * + * @return the number of hits + */ public int hits() { return hits; } + /** + * Retrieves the result channel. + * + * @return the result channel + */ public TextChannel resultChannel() { return resultChannel; } + /** + * Retrieves the last seen time. + * + * @return the last seen time + */ public Instant lastSeen() { return lastSeen; } + /** + * Retrieves the localization context. + * + * @return the localization context + */ public LocalizationContext loc() { return loc; } diff --git a/src/main/java/de/chojo/repbot/commands/scan/util/Scanner.java b/src/main/java/de/chojo/repbot/commands/scan/util/Scanner.java index 065513a8c..0f71be718 100644 --- a/src/main/java/de/chojo/repbot/commands/scan/util/Scanner.java +++ b/src/main/java/de/chojo/repbot/commands/scan/util/Scanner.java @@ -36,8 +36,15 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Class responsible for scanning messages in a channel. + */ public class Scanner { + /** + * The interval in milliseconds between scan operations. + */ public static final int INTERVAL_MS = 2000; + private static final int SCAN_THREADS = 10; private static final long THREAD_MAX_SEEN_SECONDS = 30L; private static final Logger log = getLogger(Scan.class); @@ -56,6 +63,12 @@ public class Scanner { private final Configuration configuration; private MessageAnalyzer messageAnalyzer; + /** + * Constructs a new Scanner. + * + * @param guilds the guilds provider + * @param configuration the bot configuration + */ public Scanner(Guilds guilds, Configuration configuration) { this.guilds = guilds; this.configuration = configuration; @@ -66,6 +79,14 @@ public Scanner(Guilds guilds, Configuration configuration) { }, 1, 1, TimeUnit.SECONDS); } + /** + * Initiates a scan of a channel. + * + * @param event the slash command interaction event + * @param context the event context + * @param channel the text channel to scan + * @param messageCount the number of messages to scan + */ public void scanChannel(SlashCommandInteractionEvent event, EventContext context, TextChannel channel, int messageCount) { if (PermissionErrorHandler.assertAndHandle(channel, context.guildLocalizer(), configuration, Permission.MESSAGE_SEND, Permission.VIEW_CHANNEL, Permission.VIEW_CHANNEL, Permission.MESSAGE_HISTORY)) { @@ -77,6 +98,13 @@ public void scanChannel(SlashCommandInteractionEvent event, EventContext context preSchedule(context, channel, messageCount); } + /** + * Prepares the scheduling of a scan. + * + * @param context the event context + * @param channel the text channel to scan + * @param messageCount the number of messages to scan + */ private void preSchedule(EventContext context, TextChannel channel, int messageCount) { var history = channel.getHistory(); var pattern = guilds.guild(channel.getGuild()).settings().thanking().thankwords().thankwordPattern(); @@ -84,6 +112,15 @@ private void preSchedule(EventContext context, TextChannel channel, int messageC schedule(history, context, pattern, channel, messageCount); } + /** + * Schedules a scan process. + * + * @param history the message history + * @param context the event context + * @param pattern the pattern to match + * @param reportChannel the channel to report progress + * @param calls the number of calls to make + */ private void schedule(MessageHistory history, EventContext context, Pattern pattern, TextChannel reportChannel, int calls) { var progressMessage = reportChannel.sendMessage("```ANSI\n" + context.localize("command.scan.scanner.message.progress", @@ -95,22 +132,48 @@ private void schedule(MessageHistory history, EventContext context, Pattern patt worker.schedule(() -> processScan(scanProcess), 0, TimeUnit.SECONDS); } + /** + * Checks if a scan is active for a given guild. + * + * @param guild the guild to check + * @return true if a scan is active, false otherwise + */ public boolean isActive(Guild guild) { return activeScans.stream().anyMatch(p -> p.guild().getIdLong() == guild.getIdLong()); } + /** + * Sets a scan process as active. + * + * @param process the scan process to set as active + */ public void setActive(ScanProcess process) { activeScans.add(process); } + /** + * Sets a scan process as inactive. + * + * @param process the scan process to set as inactive + */ public void setInactive(ScanProcess process) { activeScans.remove(process); } + /** + * Sets all scan processes for a guild as inactive. + * + * @param guild the guild to set as inactive + */ public void setInactive(Guild guild) { activeScans.removeIf(p -> p.guild().getIdLong() == guild.getIdLong()); } + /** + * Processes a scan. + * + * @param scan the scan process to execute + */ private void processScan(ScanProcess scan) { if (cancel.remove(scan.guild().getIdLong())) { canceled.add(scan); @@ -134,6 +197,9 @@ private void processScan(ScanProcess scan) { } } + /** + * Finishes completed scan tasks. + */ private void finishTasks() { if (finished.isEmpty()) return; var scan = finished.poll(); @@ -151,6 +217,9 @@ private void finishTasks() { scan.resultChannel().sendMessageEmbeds(embed).setMessageReference(scan.progressMessage()).queue(); } + /** + * Finishes canceled scan tasks. + */ private void finishCanceledTasks() { if (canceled.isEmpty()) return; var scan = canceled.poll(); @@ -164,24 +233,48 @@ private void finishCanceledTasks() { scan.resultChannel().sendMessageEmbeds(embed).setMessageReference(scan.progressMessage()).queue(); } + /** + * Checks if a scan is running for a given guild. + * + * @param guild the guild to check + * @return true if a scan is running, false otherwise + */ public boolean isRunning(Guild guild) { return isActive(guild); } + /** + * Cancels a scan for a given guild. + * + * @param guild the guild to cancel the scan for + */ public void cancelScan(Guild guild) { setInactive(guild); cancel.add(guild.getIdLong()); } + /** + * Finishes a scan process. + * + * @param scanProcess the scan process to finish + */ public void finishScan(ScanProcess scanProcess) { setInactive(scanProcess); finished.add(scanProcess); } + /** + * Initializes the scanner with a message analyzer. + * + * @param messageAnalyzer the message analyzer + */ public void lateInit(MessageAnalyzer messageAnalyzer) { this.messageAnalyzer = messageAnalyzer; } + /** + * Checks for and handles stuck scan tasks. + */ private void checkStuckTasks() { for (var activeScan : activeScans) { if (activeScan.lastSeen().isAfter(Instant.now().minus(THREAD_MAX_SEEN_SECONDS, ChronoUnit.SECONDS))) { @@ -195,6 +288,11 @@ private void checkStuckTasks() { } } + /** + * Checks if the scan thread limit has been reached. + * + * @return true if the limit has been reached, false otherwise + */ public boolean limitReached() { return activeScans.size() >= SCAN_THREADS; } diff --git a/src/main/java/de/chojo/repbot/commands/setup/Setup.java b/src/main/java/de/chojo/repbot/commands/setup/Setup.java index d847d46ee..3af6a31de 100644 --- a/src/main/java/de/chojo/repbot/commands/setup/Setup.java +++ b/src/main/java/de/chojo/repbot/commands/setup/Setup.java @@ -21,9 +21,19 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Command for setting up the bot in a guild. + */ public class Setup extends SlashCommand { private static final Logger log = getLogger(Setup.class); + /** + * Constructs a new Setup command. + * + * @param guilds the guilds provider + * @param thankwordsContainer the container for thank words + * @param configuration the bot configuration + */ public Setup(Guilds guilds, ThankwordsContainer thankwordsContainer, Configuration configuration) { super(Slash.of("setup", "command.setup.description") .guildOnly() @@ -31,6 +41,13 @@ public Setup(Guilds guilds, ThankwordsContainer thankwordsContainer, Configurati .command(new Start(guilds, thankwordsContainer, configuration))); } + /** + * Creates a new Setup command instance. + * + * @param guilds the guilds provider + * @param configuration the bot configuration + * @return a new Setup command instance + */ public static Setup of(Guilds guilds, Configuration configuration) { ThankwordsContainer thankwordsContainer; try { diff --git a/src/main/java/de/chojo/repbot/commands/setup/handler/Start.java b/src/main/java/de/chojo/repbot/commands/setup/handler/Start.java index dc3e1393d..5e49748b1 100644 --- a/src/main/java/de/chojo/repbot/commands/setup/handler/Start.java +++ b/src/main/java/de/chojo/repbot/commands/setup/handler/Start.java @@ -36,17 +36,34 @@ import java.util.Locale; import java.util.stream.Collectors; +/** + * Handler for the "start setup" slash command. + * This command initiates the setup process for the bot. + */ public class Start implements SlashHandler { private final Guilds guilds; private final ThankwordsContainer thankwordsContainer; private final Configuration configuration; + /** + * Constructs a new Start handler. + * + * @param guilds the guilds provider + * @param thankwordsContainer the thankwords container + * @param configuration the bot configuration + */ public Start(Guilds guilds, ThankwordsContainer thankwordsContainer, Configuration configuration) { this.guilds = guilds; this.thankwordsContainer = thankwordsContainer; this.configuration = configuration; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { PermissionErrorHandler.assertAndHandle(event.getChannel().asGuildMessageChannel(), context.guildLocalizer(), @@ -56,6 +73,12 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont .startDialog(event.getUser(), event.getChannel().asGuildMessageChannel(), getConversation(context)); } + /** + * Builds the conversation for the setup process. + * + * @param context the event context + * @return the conversation + */ private Conversation getConversation(EventContext context) { var builder = ConversationBuilder.builder( Step.button("**$%s$**%n$%s$".formatted("command.setup.dialog.welcome", "command.setup.message.continueToProceed"), @@ -70,11 +93,23 @@ private Conversation getConversation(EventContext context) { return builder.build(); } + /** + * Builds the step for selecting the language. + * + * @param context the event context + * @return the step + */ private Step buildSelectLanguage(EventContext context) { return Step.button("command.setup.message.language", but -> buildLanguageButtons(but, context)) .build(); } + /** + * Builds the language selection buttons. + * + * @param buttons the button dialog + * @param context the event context + */ private void buildLanguageButtons(ButtonDialog buttons, EventContext context) { for (var language : context.guildLocalizer().localizer().languages()) { buttons.add(Button.of(ButtonStyle.PRIMARY, language.getLocale(), language.getNativeName()), @@ -87,6 +122,11 @@ private void buildLanguageButtons(ButtonDialog buttons, EventContext context) { } } + /** + * Builds the step for setting roles. + * + * @return the step + */ private Step buildRoles() { return Step .message("command.setup.message.roles".stripIndent(), this::buildRolesButton) @@ -95,6 +135,12 @@ private Step buildRoles() { .build(); } + /** + * Builds the roles button. + * + * @param context the conversation context + * @return the result + */ private Result buildRolesButton(ConversationContext context) { var args = ArgumentUtil.parseQuotedArgs(context.getContentRaw(), true); if (args.length != 2) { @@ -110,6 +156,14 @@ private Result buildRolesButton(ConversationContext context) { .orElseGet(() -> responseInvalid(context, "error.invalidNumber")); } + /** + * Responds with a message indicating the role was added. + * + * @param context the conversation context + * @param role the role + * @param reputation the reputation points + * @return the result + */ @NotNull private Result responseRolesSubAdded(ConversationContext context, Role role, Integer reputation) { guilds.guild(context.getGuild()).settings().ranks().add(role, reputation); @@ -120,12 +174,22 @@ private Result responseRolesSubAdded(ConversationContext context, Role role, Int return Result.freeze(); } + /** + * Builds the step for loading default thankwords. + * + * @return the step + */ private Step buildLoadDefaults() { return Step.button("command.setup.message.loadDefaults", this::buildLoadDefaultsButton) .build(); } + /** + * Builds the load defaults button. + * + * @param buttons the button dialog + */ private void buildLoadDefaultsButton(ButtonDialog buttons) { var languages = thankwordsContainer.getAvailableLanguages(); for (var language : languages) { @@ -144,12 +208,22 @@ private void buildLoadDefaultsButton(ButtonDialog buttons) { buttons.add(Button.success("done", "word.done"), ctx -> Result.proceed(5)); } + /** + * Builds the step for setting channels. + * + * @return the step + */ private Step buildChannels() { return Step.button("command.setup.message.channels", this::buildChannelsButton) .message(this::handleChannels) .build(); } + /** + * Builds the channels button. + * + * @param buttons the button dialog + */ private void buildChannelsButton(ButtonDialog buttons) { buttons.add(new ComponenAction(Button.success("done", "word.done"), ctx -> { ctx.reply(ctx.localize("command.setup.message.complete")) @@ -163,6 +237,12 @@ private void buildChannelsButton(ButtonDialog buttons) { }); } + /** + * Handles the channels input. + * + * @param context the conversation context + * @return the result + */ private Result handleChannels(ConversationContext context) { var args = context.getContentRaw().replaceAll("\\s+", " ").split("\\s"); var channels = DiscordResolver.getTextChannels(context.getGuild(), List.of(args)); @@ -180,6 +260,13 @@ private Result handleChannels(ConversationContext context) { return Result.freeze(); } + /** + * Responds with an invalid input message. + * + * @param context the conversation context + * @param s the message key + * @return the result + */ @NotNull private Result responseInvalid(ConversationContext context, String s) { context.reply(context.localize(s)).queue(); diff --git a/src/main/java/de/chojo/repbot/commands/thankwords/Thankwords.java b/src/main/java/de/chojo/repbot/commands/thankwords/Thankwords.java index a8f58f69d..5ed354c65 100644 --- a/src/main/java/de/chojo/repbot/commands/thankwords/Thankwords.java +++ b/src/main/java/de/chojo/repbot/commands/thankwords/Thankwords.java @@ -26,10 +26,23 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Class representing the Thankwords slash command. + */ public class Thankwords extends SlashCommand { + /** + * Logger instance for logging events. + */ private static final Logger log = getLogger(Thankwords.class); + /** + * Constructs a new Thankwords instance. + * + * @param messageAnalyzer the message analyzer + * @param guilds the guilds provider + * @param thankwordsContainer the thank words container + */ private Thankwords(MessageAnalyzer messageAnalyzer, Guilds guilds, ThankwordsContainer thankwordsContainer) { super(Slash.of("thankwords", "command.thankwords.description") .guildOnly() @@ -54,6 +67,13 @@ private Thankwords(MessageAnalyzer messageAnalyzer, Guilds guilds, ThankwordsCon ); } + /** + * Creates a new Thankwords instance. + * + * @param messageAnalyzer the message analyzer + * @param guilds the guilds provider + * @return a new Thankwords instance + */ public static Thankwords of(MessageAnalyzer messageAnalyzer, Guilds guilds) { ThankwordsContainer thankwordsContainer; try { @@ -65,6 +85,12 @@ public static Thankwords of(MessageAnalyzer messageAnalyzer, Guilds guilds) { return new Thankwords(messageAnalyzer, guilds, thankwordsContainer); } + /** + * Loads the ThankwordsContainer from a JSON file. + * + * @return the loaded ThankwordsContainer + * @throws IOException if an I/O error occurs + */ public static ThankwordsContainer loadContainer() throws IOException { try (var input = Thankwords.class.getClassLoader().getResourceAsStream("Thankswords.json")) { return new ObjectMapper() diff --git a/src/main/java/de/chojo/repbot/commands/thankwords/handler/Add.java b/src/main/java/de/chojo/repbot/commands/thankwords/handler/Add.java index 62e054f8a..ec33927dd 100644 --- a/src/main/java/de/chojo/repbot/commands/thankwords/handler/Add.java +++ b/src/main/java/de/chojo/repbot/commands/thankwords/handler/Add.java @@ -15,13 +15,27 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +/** + * Handler for the "add thankword" slash command, which adds a thankword pattern. + */ public class Add implements SlashHandler { private final Guilds guilds; + /** + * Constructs an Add handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Add(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var pattern = event.getOption("pattern").getAsString(); diff --git a/src/main/java/de/chojo/repbot/commands/thankwords/handler/Check.java b/src/main/java/de/chojo/repbot/commands/thankwords/handler/Check.java index a1e875a23..65b799b88 100644 --- a/src/main/java/de/chojo/repbot/commands/thankwords/handler/Check.java +++ b/src/main/java/de/chojo/repbot/commands/thankwords/handler/Check.java @@ -16,15 +16,30 @@ import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the "check" slash command, which checks a message for thankwords. + */ public class Check implements SlashHandler { private final Guilds guilds; private final MessageAnalyzer messageAnalyzer; + /** + * Constructs a Check handler with the specified guilds provider and message analyzer. + * + * @param guilds the guilds provider + * @param messageAnalyzer the message analyzer + */ public Check(Guilds guilds, MessageAnalyzer messageAnalyzer) { this.guilds = guilds; this.messageAnalyzer = messageAnalyzer; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var settings = guilds.guild(event.getGuild()).settings(); @@ -49,6 +64,12 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont event.replyEmbeds(builder.build()).queue(); } + /** + * Processes the message analysis result and builds the response embed. + * + * @param result the match analyzer result + * @param builder the localized embed builder + */ private void processMessage(MatchAnalyzerResult result, LocalizedEmbedBuilder builder) { if (result.thankType() == ThankType.FUZZY) { for (var receiver : result.asFuzzy().weightedReceiver()) { diff --git a/src/main/java/de/chojo/repbot/commands/thankwords/handler/List.java b/src/main/java/de/chojo/repbot/commands/thankwords/handler/List.java index 41dff008a..e6d00250e 100644 --- a/src/main/java/de/chojo/repbot/commands/thankwords/handler/List.java +++ b/src/main/java/de/chojo/repbot/commands/thankwords/handler/List.java @@ -15,13 +15,27 @@ import java.util.stream.Collectors; +/** + * Handler for the list thank words command. + */ public class List implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new List handler with the specified Guilds provider. + * + * @param guilds the Guilds provider + */ public List(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event to list thank words. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var pattern = getGuildPattern(event.getGuild()); @@ -30,6 +44,12 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont event.reply(context.localize("command.thankwords.list.message.list") + "\n" + pattern).queue(); } + /** + * Retrieves the thank words pattern for the specified guild. + * + * @param guild the Guild to get the thank words pattern from + * @return a string containing the thank words pattern, or null if not available + */ @Nullable private String getGuildPattern(Guild guild) { return guilds.guild(guild).settings().thanking().thankwords().words().stream() diff --git a/src/main/java/de/chojo/repbot/commands/thankwords/handler/LoadDefault.java b/src/main/java/de/chojo/repbot/commands/thankwords/handler/LoadDefault.java index e139c7683..ee41acc20 100644 --- a/src/main/java/de/chojo/repbot/commands/thankwords/handler/LoadDefault.java +++ b/src/main/java/de/chojo/repbot/commands/thankwords/handler/LoadDefault.java @@ -17,15 +17,30 @@ import java.util.Locale; import java.util.stream.Collectors; +/** + * Handler for the load default thank words command. + */ public class LoadDefault implements SlashHandler { private final Guilds guilds; private final ThankwordsContainer thankwordsContainer; + /** + * Constructs a new LoadDefault handler with the specified Guilds provider and ThankwordsContainer. + * + * @param guilds the Guilds provider + * @param thankwordsContainer the ThankwordsContainer + */ public LoadDefault(Guilds guilds, ThankwordsContainer thankwordsContainer) { this.guilds = guilds; this.thankwordsContainer = thankwordsContainer; } + /** + * Handles the slash command interaction event to load default thank words. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var languageOption = event.getOption("language"); @@ -51,6 +66,12 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont event.reply(context.localize("command.thankwords.loaddefault.message.added") + wordsJoined).queue(); } + /** + * Handles the auto-complete interaction event for the load default thank words command. + * + * @param event the CommandAutoCompleteInteractionEvent + * @param context the EventContext + */ @Override public void onAutoComplete(CommandAutoCompleteInteractionEvent event, EventContext context) { var option = event.getFocusedOption(); diff --git a/src/main/java/de/chojo/repbot/commands/thankwords/handler/Remove.java b/src/main/java/de/chojo/repbot/commands/thankwords/handler/Remove.java index 2cad610e2..cca2acf87 100644 --- a/src/main/java/de/chojo/repbot/commands/thankwords/handler/Remove.java +++ b/src/main/java/de/chojo/repbot/commands/thankwords/handler/Remove.java @@ -17,13 +17,27 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +/** + * Handles the removal of thank words from a guild's settings. + */ public class Remove implements SlashHandler { private final Guilds guilds; + /** + * Constructs a Remove handler with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Remove(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event for removing a thank word pattern. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var pattern = event.getOption("pattern").getAsString(); @@ -45,6 +59,12 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont .queue(); } + /** + * Handles the auto-complete interaction event for thank word patterns. + * + * @param event the auto-complete interaction event + * @param context the event context + */ @Override public void onAutoComplete(CommandAutoCompleteInteractionEvent event, EventContext context) { var option = event.getFocusedOption(); diff --git a/src/main/java/de/chojo/repbot/commands/top/Top.java b/src/main/java/de/chojo/repbot/commands/top/Top.java index b696080c0..da62e059b 100644 --- a/src/main/java/de/chojo/repbot/commands/top/Top.java +++ b/src/main/java/de/chojo/repbot/commands/top/Top.java @@ -11,7 +11,16 @@ import de.chojo.repbot.commands.top.handler.Show; import de.chojo.repbot.dao.provider.Guilds; +/** + * Class representing the Top slash command. + */ public class Top extends SlashCommand { + + /** + * Constructs a new Top instance. + * + * @param guilds the guilds provider + */ public Top(Guilds guilds) { super(Slash.of("top", "command.top.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/top/handler/Show.java b/src/main/java/de/chojo/repbot/commands/top/handler/Show.java index 48afc1c46..352ff6a15 100644 --- a/src/main/java/de/chojo/repbot/commands/top/handler/Show.java +++ b/src/main/java/de/chojo/repbot/commands/top/handler/Show.java @@ -15,7 +15,6 @@ import de.chojo.repbot.dao.pagination.GuildRanking; import de.chojo.repbot.dao.provider.Guilds; import net.dv8tion.jda.api.entities.Guild; -import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; import net.dv8tion.jda.api.utils.messages.MessageEditData; @@ -24,14 +23,29 @@ import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +/** + * Handler for the "show top" slash command. + * This command displays the top rankings for the guild based on reputation. + */ public class Show implements SlashHandler { private static final int TOP_PAGE_SIZE = 10; private final Guilds guilds; + /** + * Constructs a new Show handler. + * + * @param guilds the guilds provider + */ public Show(Guilds guilds) { this.guilds = guilds; } + /** + * Handles the slash command interaction event. + * + * @param event the slash command interaction event + * @param context the event context + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { var guild = guilds.guild(event.getGuild()); @@ -52,6 +66,13 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont registerPage(ranking, event, context); } + /** + * Registers a page for the ranking. + * + * @param guildRanking the guild ranking + * @param event the slash command interaction event + * @param context the event context + */ public static void registerPage(GuildRanking guildRanking, SlashCommandInteractionEvent event, EventContext context) { context.registerPage(new PageBag(guildRanking.pages()) { @Override @@ -78,12 +99,26 @@ public CompletableFuture buildEmptyPage() { }, true); } + /** + * Creates a base embed builder for the ranking. + * + * @param guildRanking the guild ranking + * @param context the event context + * @param guild the guild + * @return the localized embed builder + */ private static LocalizedEmbedBuilder createBaseBuilder(GuildRanking guildRanking, EventContext context, Guild guild) { return new LocalizedEmbedBuilder(context.guildLocalizer()) .setTitle(guildRanking.title(), Replacement.create("GUILD", guild.getName())) .setColor(Color.CYAN); } + /** + * Handles the auto-complete interaction event. + * + * @param event the auto-complete interaction event + * @param context the event context + */ @Override public void onAutoComplete(CommandAutoCompleteInteractionEvent event, EventContext context) { var option = event.getFocusedOption(); diff --git a/src/main/java/de/chojo/repbot/config/ConfigFile.java b/src/main/java/de/chojo/repbot/config/ConfigFile.java index 8ed1e64c2..36807780f 100644 --- a/src/main/java/de/chojo/repbot/config/ConfigFile.java +++ b/src/main/java/de/chojo/repbot/config/ConfigFile.java @@ -17,6 +17,9 @@ import de.chojo.repbot.config.elements.PresenceSettings; import de.chojo.repbot.config.elements.SelfCleanup; +/** + * Configuration file class that holds various settings for the application. + */ @SuppressWarnings({"FieldMayBeFinal", "CanBeFinal"}) public class ConfigFile { private BaseSettings baseSettings = new BaseSettings(); @@ -31,46 +34,107 @@ public class ConfigFile { private SelfCleanup selfcleanup = new SelfCleanup(); private Cleanup cleanup = new Cleanup(); + /** + * Creates a new configuration file with default values. + */ + public ConfigFile(){ + } + + /** + * Returns the base settings. + * + * @return the base settings + */ public BaseSettings baseSettings() { return baseSettings; } + /** + * Returns the presence settings. + * + * @return the presence settings + */ public PresenceSettings presence() { return presenceSettings; } + /** + * Returns the analyzer settings. + * + * @return the analyzer settings + */ public AnalyzerSettings analyzerSettings() { return analyzerSettings; } + /** + * Returns the database settings. + * + * @return the database settings + */ public Database database() { return database; } + /** + * Returns the magic image settings. + * + * @return the magic image settings + */ public MagicImage magicImage() { return magicImage; } + /** + * Returns the badges settings. + * + * @return the badges settings + */ public Badges badges() { return badges; } + /** + * Returns the links settings. + * + * @return the links settings + */ public Links links() { return links; } + /** + * Returns the botlist settings. + * + * @return the botlist settings + */ public Botlist botlist() { return botlist; } + /** + * Returns the self-cleanup settings. + * + * @return the self-cleanup settings + */ public SelfCleanup selfCleanup() { return selfcleanup; } + /** + * Returns the API settings. + * + * @return the API settings + */ public Api api() { return api; } + /** + * Returns the cleanup settings. + * + * @return the cleanup settings + */ public Cleanup cleanup() { return cleanup; } diff --git a/src/main/java/de/chojo/repbot/config/Configuration.java b/src/main/java/de/chojo/repbot/config/Configuration.java index 5f3119600..0d578675a 100644 --- a/src/main/java/de/chojo/repbot/config/Configuration.java +++ b/src/main/java/de/chojo/repbot/config/Configuration.java @@ -34,11 +34,17 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Configuration class responsible for loading and managing the bot's configuration settings. + */ public class Configuration { private static final Logger log = getLogger(Configuration.class); private final ObjectMapper objectMapper; private ConfigFile configFile; + /** + * Constructs a Configuration instance and initializes the ObjectMapper. + */ private Configuration() { objectMapper = JsonMapper.builder() .configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true) @@ -49,12 +55,20 @@ private Configuration() { .setDefaultPrettyPrinter(new DefaultPrettyPrinter()); } + /** + * Creates and initializes a Configuration instance. + * + * @return a new Configuration instance + */ public static Configuration create() { var configuration = new Configuration(); configuration.reload(); return configuration; } + /** + * Reloads the configuration from the file and saves it. + */ public void reload() { try { reloadFile(); @@ -69,15 +83,30 @@ public void reload() { } } + /** + * Saves the current configuration to the file. + * + * @throws IOException if an I/O error occurs + */ private void save() throws IOException { objectMapper.writerWithDefaultPrettyPrinter().writeValues(getConfig().toFile()).write(configFile); } + /** + * Reloads the configuration file and ensures consistency. + * + * @throws IOException if an I/O error occurs + */ private void reloadFile() throws IOException { forceConsistency(); configFile = objectMapper.readValue(getConfig().toFile(), ConfigFile.class); } + /** + * Ensures the configuration file and its directories exist. + * + * @throws IOException if an I/O error occurs + */ private void forceConsistency() throws IOException { Files.createDirectories(getConfig().getParent()); if (!getConfig().toFile().exists()) { @@ -88,6 +117,11 @@ private void forceConsistency() throws IOException { } } + /** + * Gets the path to the configuration file. + * + * @return the path to the configuration file + */ private Path getConfig() { var home = new File(".").getAbsoluteFile().getParentFile().toPath(); var property = System.getProperty("bot.config"); @@ -98,46 +132,101 @@ private Path getConfig() { return Paths.get(home.toString(), property); } + /** + * Gets the database configuration. + * + * @return the database configuration + */ public Database database() { return configFile.database(); } + /** + * Gets the base settings configuration. + * + * @return the base settings configuration + */ public BaseSettings baseSettings() { return configFile.baseSettings(); } + /** + * Gets the analyzer settings configuration. + * + * @return the analyzer settings configuration + */ public AnalyzerSettings analyzerSettings() { return configFile.analyzerSettings(); } + /** + * Gets the magic image configuration. + * + * @return the magic image configuration + */ public MagicImage magicImage() { return configFile.magicImage(); } + /** + * Gets the badges configuration. + * + * @return the badges configuration + */ public Badges badges() { return configFile.badges(); } + /** + * Gets the links configuration. + * + * @return the links configuration + */ public Links links() { return configFile.links(); } + /** + * Gets the botlist configuration. + * + * @return the botlist configuration + */ public Botlist botlist() { return configFile.botlist(); } + /** + * Gets the presence settings configuration. + * + * @return the presence settings configuration + */ public PresenceSettings presence() { return configFile.presence(); } + /** + * Gets the self-cleanup configuration. + * + * @return the self-cleanup configuration + */ public SelfCleanup selfCleanup() { return configFile.selfCleanup(); } + /** + * Gets the API configuration. + * + * @return the API configuration + */ public Api api() { return configFile.api(); } + /** + * Gets the cleanup configuration. + * + * @return the cleanup configuration + */ public Cleanup cleanup() { return configFile.cleanup(); } diff --git a/src/main/java/de/chojo/repbot/config/elements/AnalyzerSettings.java b/src/main/java/de/chojo/repbot/config/elements/AnalyzerSettings.java index c46704e14..016d5c0a6 100644 --- a/src/main/java/de/chojo/repbot/config/elements/AnalyzerSettings.java +++ b/src/main/java/de/chojo/repbot/config/elements/AnalyzerSettings.java @@ -5,6 +5,9 @@ */ package de.chojo.repbot.config.elements; +/** + * Configuration settings for the analyzer. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) public class AnalyzerSettings { private int historySize = 100; @@ -12,18 +15,44 @@ public class AnalyzerSettings { private int latestMaxHours = 12; private float minFuzzyScore = 0.9f; + /** + * Creates a new analyzer configuration with default values. + */ + public AnalyzerSettings(){ + } + + /** + * Gets the maximum number of hours for the latest entries. + * + * @return the maximum number of hours for the latest entries + */ public int latestMaxHours() { return latestMaxHours; } + /** + * Gets the minimum fuzzy score. + * + * @return the minimum fuzzy score + */ public float minFuzzyScore() { return minFuzzyScore; } + /** + * Gets the history size, limited to a maximum of 100. + * + * @return the history size + */ public int historySize() { return Math.min(historySize, 100); } + /** + * Gets the number of voice members. + * + * @return the number of voice members + */ public int voiceMembers() { return voiceMembers; } diff --git a/src/main/java/de/chojo/repbot/config/elements/Api.java b/src/main/java/de/chojo/repbot/config/elements/Api.java index 839c13f1a..e6208ec14 100644 --- a/src/main/java/de/chojo/repbot/config/elements/Api.java +++ b/src/main/java/de/chojo/repbot/config/elements/Api.java @@ -5,20 +5,44 @@ */ package de.chojo.repbot.config.elements; -@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "MismatchedReadAndWriteOfArray"}) +/** + * Configuration class for the API settings. + */ +@SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) public class Api { private String host = "0.0.0.0"; private int port = 8888; private String url = "https://repbot.chojo.de"; + /** + * Creates a new API configuration with default values. + */ + public Api(){ + } + + /** + * Gets the host address for the API. + * + * @return the host address + */ public String host() { return host; } + /** + * Gets the port number for the API. + * + * @return the port number + */ public int port() { return port; } + /** + * Gets the URL for the API. + * + * @return the URL + */ public String url() { return url; } diff --git a/src/main/java/de/chojo/repbot/config/elements/Badges.java b/src/main/java/de/chojo/repbot/config/elements/Badges.java index 7216382ae..b9c62e8a2 100644 --- a/src/main/java/de/chojo/repbot/config/elements/Badges.java +++ b/src/main/java/de/chojo/repbot/config/elements/Badges.java @@ -7,11 +7,20 @@ import java.util.Optional; +/** + * Configuration class for the badges. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "MismatchedReadAndWriteOfArray"}) public class Badges { private boolean enables = true; private String[] badges = new String[0]; + /** + * Creates a new badge configuration with default values. + */ + public Badges(){ + } + /** * Retrieve the badge for the rank. * diff --git a/src/main/java/de/chojo/repbot/config/elements/BaseSettings.java b/src/main/java/de/chojo/repbot/config/elements/BaseSettings.java index f2011f45c..02482551f 100644 --- a/src/main/java/de/chojo/repbot/config/elements/BaseSettings.java +++ b/src/main/java/de/chojo/repbot/config/elements/BaseSettings.java @@ -8,20 +8,45 @@ import java.util.ArrayList; import java.util.List; +/** + * Configuration class for the base settings. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal", "MismatchedQueryAndUpdateOfCollection"}) public class BaseSettings { private String token = ""; private List botOwner = new ArrayList<>(); private long botGuild = 0L; + /** + * Creates a new base configuration with default values. + */ + public BaseSettings(){ + } + + /** + * Gets the bot token. + * + * @return the bot token + */ public String token() { return token; } + /** + * Checks if the given ID is a bot owner. + * + * @param id the ID to check + * @return true if the ID is a bot owner, false otherwise + */ public boolean isOwner(long id) { return botOwner.contains(id); } + /** + * Gets the bot guild ID. + * + * @return the bot guild ID + */ public long botGuild() { return botGuild; } diff --git a/src/main/java/de/chojo/repbot/config/elements/Botlist.java b/src/main/java/de/chojo/repbot/config/elements/Botlist.java index 270a2235a..dc05030a3 100644 --- a/src/main/java/de/chojo/repbot/config/elements/Botlist.java +++ b/src/main/java/de/chojo/repbot/config/elements/Botlist.java @@ -7,34 +7,93 @@ import de.chojo.jdautil.botlist.BotListConfig; +/** + * Configuration class for botlist settings. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) public class Botlist { + /** + * Indicates whether submissions are enabled. + */ private boolean submit; + + /** + * Configuration for top.gg. + */ private BotListConfig topGg = new BotListConfig("top.gg", "", "", 264445053596991498L, "", ""); + + /** + * Configuration for discord.bots.gg. + */ private BotListConfig discordBotsGg = new BotListConfig("discord.bots.gg", "", "", 110373943822540800L, "", ""); + + /** + * Configuration for discordbotlist.com. + */ private BotListConfig discordBotlistCom = new BotListConfig("discordbotlist.com", "", "", 450100127256936458L, "", ""); + + /** + * Configuration for botlist.me. + */ private BotListConfig botListMe = new BotListConfig("discordbotlist.com", "", "", 698637043240009738L, "", ""); + /** + * Creates a new botlist configuration with default values. + */ + public Botlist(){ + } + + /** + * Checks if submissions are enabled. + * + * @return true if submissions are enabled, false otherwise + */ public boolean isSubmit() { return submit; } + /** + * Gets the configuration for top.gg. + * + * @return the top.gg configuration + */ public BotListConfig topGg() { return topGg; } + /** + * Gets the configuration for discord.bots.gg. + * + * @return the discord.bots.gg configuration + */ public BotListConfig discordBotsGg() { return discordBotsGg; } + /** + * Gets the configuration for discordbotlist.com. + * + * @return the discordbotlist.com configuration + */ public BotListConfig discordBotlistCom() { return discordBotlistCom; } + /** + * Gets the configuration for botlist.me. + * + * @return the botlist.me configuration + */ public BotListConfig botListMe() { return discordBotlistCom; } + /** + * Checks if the given ID matches any botlist guild ID. + * + * @param id the ID to check + * @return true if the ID matches a botlist guild ID, false otherwise + */ public boolean isBotlistGuild(long id) { for (var botlist : botlists()) { if (botlist.guildId() == id) { @@ -45,6 +104,11 @@ public boolean isBotlistGuild(long id) { return false; } + /** + * Gets an array of all botlist configurations. + * + * @return an array of botlist configurations + */ public BotListConfig[] botlists() { return new BotListConfig[]{topGg, discordBotsGg, discordBotlistCom, botListMe}; } diff --git a/src/main/java/de/chojo/repbot/config/elements/Cleanup.java b/src/main/java/de/chojo/repbot/config/elements/Cleanup.java index dd34040c3..926d09b6a 100644 --- a/src/main/java/de/chojo/repbot/config/elements/Cleanup.java +++ b/src/main/java/de/chojo/repbot/config/elements/Cleanup.java @@ -5,37 +5,68 @@ */ package de.chojo.repbot.config.elements; +/** + * Configuration class for the cleanup settings. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) public class Cleanup { + /** + * The hours after an entry in the analyzer\_log table gets deleted. + */ private int analyzerLogHours = 24; + + /** + * The days after an entry in the gdpr\_log table gets deleted. + */ private int gdprDays = 90; + + /** + * The hours after an entry in the voice\_activity table gets deleted. + */ private int voiceActivityHours = 24; + /** + * The days after an entry in the cleanup\_schedule table gets deleted. + */ private int cleanupScheduleDays = 14; /** - * The hours after an entry in the analyzer_log table gets deleted. + * Creates a new cleanup configuration with default values. + */ + public Cleanup(){ + } + + /** + * Returns the hours after an entry in the analyzer\_log table gets deleted. + * + * @return the analyzer log hours */ public int analyzerLogHours() { return analyzerLogHours; } /** - * The days after an entry in the gdpr_log table gets deleted. + * Returns the days after an entry in the gdpr\_log table gets deleted. + * + * @return the GDPR days */ public int gdprDays() { return gdprDays; } /** - * The hours after an entry in the voice_activity table gets deleted. + * Returns the hours after an entry in the voice\_activity table gets deleted. + * + * @return the voice activity hours */ public int voiceActivityHours() { return voiceActivityHours; } /** - * The days after an entry in the cleanup_schedule table gets deleted. + * Returns the days after an entry in the cleanup\_schedule table gets deleted. + * + * @return the cleanup schedule days */ public int cleanupScheduleDays() { return cleanupScheduleDays; diff --git a/src/main/java/de/chojo/repbot/config/elements/Database.java b/src/main/java/de/chojo/repbot/config/elements/Database.java index b53c141a6..de7ac664c 100644 --- a/src/main/java/de/chojo/repbot/config/elements/Database.java +++ b/src/main/java/de/chojo/repbot/config/elements/Database.java @@ -5,41 +5,111 @@ */ package de.chojo.repbot.config.elements; - +/** + * Configuration class for the database settings. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) public class Database { + /** + * The host of the database. + */ private String host = "localhost"; + + /** + * The port of the database. + */ private String port = "5432"; + + /** + * The name of the database. + */ private String database = "db"; + + /** + * The schema of the database. + */ private String schema = "repbot"; + + /** + * The user for the database connection. + */ private String user = "user"; + + /** + * The password for the database connection. + */ private String password = "pw"; + + /** + * The size of the connection pool. + */ private int poolSize = 5; + /** + * Creates a new database configuration with default values. + */ + public Database(){ + } + + /** + * Retrieves the database host. + * + * @return the database host + */ public String host() { return host; } + /** + * Retrieves the database port. + * + * @return the database port + */ public String port() { return port; } + /** + * Retrieves the database name. + * + * @return the database name + */ public String database() { return database; } + /** + * Retrieves the database schema. + * + * @return the database schema + */ public String schema() { return schema; } + /** + * Retrieves the database user. + * + * @return the database user + */ public String user() { return user; } + /** + * Retrieves the database password. + * + * @return the database password + */ public String password() { return password; } + /** + * Retrieves the size of the connection pool. + * + * @return the connection pool size + */ public int poolSize() { return poolSize; } diff --git a/src/main/java/de/chojo/repbot/config/elements/Links.java b/src/main/java/de/chojo/repbot/config/elements/Links.java index 5b8312df8..9564af8e8 100644 --- a/src/main/java/de/chojo/repbot/config/elements/Links.java +++ b/src/main/java/de/chojo/repbot/config/elements/Links.java @@ -5,6 +5,9 @@ */ package de.chojo.repbot.config.elements; +/** + * Configuration class for the links. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) public class Links { private String tos = ""; @@ -13,22 +16,53 @@ public class Links { private String website = "https://rainbowdashlabs.github.io/reputation-bot/"; private String faq = "https://rainbowdashlabs.github.io/reputation-bot/faq"; + /** + * Creates a new links configuration with default values. + */ + public Links(){ + } + + /** + * Retrieves the Terms of Service (ToS) link. + * + * @return the ToS link as a String + */ public String tos() { return tos; } + /** + * Retrieves the invite link for the bot. + * + * @return the invite link as a String + */ public String invite() { return invite; } + /** + * Retrieves the support link. + * + * @return the support link as a String + */ public String support() { return support; } + /** + * Retrieves the website link. + * + * @return the website link as a String + */ public String website() { return website; } + /** + * Retrieves the FAQ link. + * + * @return the FAQ link as a String + */ public String faq() { return faq; } diff --git a/src/main/java/de/chojo/repbot/config/elements/MagicImage.java b/src/main/java/de/chojo/repbot/config/elements/MagicImage.java index 1cc55cc64..1c7107a32 100644 --- a/src/main/java/de/chojo/repbot/config/elements/MagicImage.java +++ b/src/main/java/de/chojo/repbot/config/elements/MagicImage.java @@ -5,26 +5,69 @@ */ package de.chojo.repbot.config.elements; - +/** + * The magic image configuration. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) public class MagicImage { + /** + * The link to the magic image. + */ private String magicImageLink = ""; + + /** + * The chance of imagining a magic image. + */ private int magicImagineChance = 10; + + /** + * The cooldown period for the magic image. + */ private int magicImageCooldown = 30; + + /** + * The schedule for deleting the magic image. + */ private int magicImageDeleteSchedule = 60; + /** + * Creates a new magic image configuration with default values. + */ + public MagicImage(){ + } + + /** + * Returns the link to the magic image. + * + * @return the magic image link + */ public String magicImageLink() { return magicImageLink; } + /** + * Returns the chance of imagining a magic image. + * + * @return the magic imagine chance + */ public int magicImagineChance() { return magicImagineChance; } + /** + * Returns the cooldown period for the magic image. + * + * @return the magic image cooldown + */ public int magicImageCooldown() { return magicImageCooldown; } + /** + * Returns the schedule for deleting the magic image. + * + * @return the magic image delete schedule + */ public int magicImageDeleteSchedule() { return magicImageDeleteSchedule; } diff --git a/src/main/java/de/chojo/repbot/config/elements/PresenceSettings.java b/src/main/java/de/chojo/repbot/config/elements/PresenceSettings.java index 09854b59f..e05d63668 100644 --- a/src/main/java/de/chojo/repbot/config/elements/PresenceSettings.java +++ b/src/main/java/de/chojo/repbot/config/elements/PresenceSettings.java @@ -13,6 +13,9 @@ import java.util.List; import java.util.concurrent.ThreadLocalRandom; +/** + * Represents the settings for the bot's presence, including activity type and status messages. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) public class PresenceSettings { private boolean active; @@ -27,42 +30,95 @@ public class PresenceSettings { Presence.of(Activity.ActivityType.LISTENING, "%analyzed_messages% messages during the last hour!") ); + /** + * Creates a new presence settings with default values. + */ + public PresenceSettings(){ + } + + /** + * Checks if the presence settings are active. + * + * @return true if active, false otherwise + */ public boolean isActive() { return active; } + /** + * Gets the list of presence statuses. + * + * @return the list of presence statuses + */ public List status() { return status; } + /** + * Gets a random presence status from the list. + * + * @return a random presence status + */ public Presence randomStatus() { if (status.isEmpty()) return Presence.of(Activity.ActivityType.WATCHING, "something"); return status.get(ThreadLocalRandom.current().nextInt(status.size())); } + /** + * Gets the interval for updating the presence status. + * + * @return the interval in minutes + */ public int interval() { return interval; } + /** + * Represents a single presence status with an activity type and text. + */ @SuppressWarnings("CanBeFinal") public static class Presence { private Activity.ActivityType type; private String text; + /** + * Constructs a Presence instance with the specified type and text. + * + * @param type the activity type + * @param text the text to display + */ @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) public Presence(@JsonProperty("type") Activity.ActivityType type, @JsonProperty("text") String text) { this.type = type; this.text = text; } + /** + * Creates a new Presence instance with the specified type and text. + * + * @param type the activity type + * @param text the text to display + * @return a new Presence instance + */ public static Presence of(Activity.ActivityType type, String text) { return new Presence(type, text); } + /** + * Gets the activity type of the presence. + * + * @return the activity type + */ public Activity.ActivityType type() { return type; } + /** + * Gets the text of the presence with replacements applied. + * + * @param replacements the list of replacements to apply + * @return the text with replacements applied + */ public String text(List replacements) { var message = text; for (var replacement : replacements) { diff --git a/src/main/java/de/chojo/repbot/config/elements/SelfCleanup.java b/src/main/java/de/chojo/repbot/config/elements/SelfCleanup.java index a0b266db7..4d5fe0813 100644 --- a/src/main/java/de/chojo/repbot/config/elements/SelfCleanup.java +++ b/src/main/java/de/chojo/repbot/config/elements/SelfCleanup.java @@ -9,37 +9,97 @@ import java.time.OffsetDateTime; import java.time.ZoneOffset; +/** + * Represents the self-cleanup configuration for the bot. + * This class provides settings for managing inactive users and prompting them for cleanup. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) public class SelfCleanup { + /** + * Indicates if the self-cleanup is active. + */ private boolean active = true; + + /** + * Number of days before prompting for cleanup. + */ private int promptDays = 3; + + /** + * Number of days before leaving after prompt. + */ private int leaveDays = 3; + + /** + * Number of days of inactivity before cleanup. + */ private int inactiveDays = 90; + /** + * Creates a new self-cleanup configuration with default values. + */ + public SelfCleanup(){ + } + + /** + * Checks if the self-cleanup is active. + * + * @return true if active, false otherwise + */ public boolean isActive() { return active; } + /** + * Retrieves the number of days before prompting for cleanup. + * + * @return the number of prompt days + */ public int promptDays() { return promptDays; } + /** + * Retrieves the number of days before leaving after prompt. + * + * @return the number of leave days + */ public int leaveDays() { return leaveDays; } + /** + * Retrieves the number of days of inactivity before cleanup. + * + * @return the number of inactive days + */ public int inactiveDays() { return inactiveDays; } + /** + * Calculates the offset date-time for the prompt days. + * + * @return the offset date-time for the prompt days + */ public OffsetDateTime getPromptDaysOffset() { return LocalDateTime.now().minusDays(promptDays()).atOffset(ZoneOffset.UTC); } + /** + * Calculates the local date-time for the leave days. + * + * @return the local date-time for the leave days + */ public LocalDateTime getLeaveDaysOffset() { return LocalDateTime.now().minusDays(leaveDays()); } + /** + * Calculates the local date-time for the inactive days. + * + * @return the local date-time for the inactive days + */ public LocalDateTime getInactiveDaysOffset() { return LocalDateTime.now().minusDays(inactiveDays()); } diff --git a/src/main/java/de/chojo/repbot/config/exception/ConfigurationException.java b/src/main/java/de/chojo/repbot/config/exception/ConfigurationException.java index f74304643..b21aa371b 100644 --- a/src/main/java/de/chojo/repbot/config/exception/ConfigurationException.java +++ b/src/main/java/de/chojo/repbot/config/exception/ConfigurationException.java @@ -5,6 +5,9 @@ */ package de.chojo.repbot.config.exception; +/** + * Exception thrown when there is a configuration error. + */ public class ConfigurationException extends RuntimeException { /** * Constructs a new runtime exception with the specified detail message. diff --git a/src/main/java/de/chojo/repbot/core/Bot.java b/src/main/java/de/chojo/repbot/core/Bot.java index d50053214..1159b09b7 100644 --- a/src/main/java/de/chojo/repbot/core/Bot.java +++ b/src/main/java/de/chojo/repbot/core/Bot.java @@ -68,6 +68,9 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Main class for the bot. + */ public class Bot { private static final Logger log = getLogger(Bot.class); private final Data data; @@ -85,6 +88,14 @@ public class Bot { private Statistic statistic; private GdprService gdprService; + /** + * Constructs a Bot instance with the specified data, threading, configuration, and localization. + * + * @param data the data + * @param threading the threading + * @param configuration the configuration + * @param localization the localization + */ private Bot(Data data, Threading threading, Configuration configuration, Localization localization) { this.data = data; this.threading = threading; @@ -92,12 +103,27 @@ private Bot(Data data, Threading threading, Configuration configuration, Localiz this.localization = localization; } + /** + * Creates and initializes a Bot instance. + * + * @param data the data + * @param threading the threading + * @param configuration the configuration + * @param localizer the localizer + * @return the created Bot instance + * @throws LoginException if a login error occurs + */ public static Bot create(Data data, Threading threading, Configuration configuration, Localization localizer) throws LoginException { var bot = new Bot(data, threading, configuration, localizer); bot.init(); return bot; } + /** + * Initializes the bot. + * + * @throws LoginException if a login error occurs + */ public void init() throws LoginException { initShardManager(); configureRestActions(); @@ -106,6 +132,9 @@ public void init() throws LoginException { initListener(); } + /** + * Configures the default actions for REST requests. + */ private void configureRestActions() { log.info("Configuring rest actions."); RestAction.setDefaultFailure(throwable -> { @@ -134,6 +163,11 @@ private void configureRestActions() { }); } + /** + * Initializes the shard manager. + * + * @throws LoginException if a login error occurs + */ private void initShardManager() throws LoginException { log.info("Initializing Shardmanager."); roleAssigner = new RoleAssigner(data.guilds(), localization.localizer()); @@ -163,6 +197,9 @@ private void initShardManager() throws LoginException { .build(); } + /** + * Initializes the services used by the bot. + */ private void initServices() { log.info("Setting up services"); var guilds = data.guilds(); @@ -184,6 +221,9 @@ private void initServices() { MetricService.create(threading.repBotWorker(), data.metrics()); } + /** + * Initializes the interactions for the bot. + */ private void initInteractions() { log.info("Setting up interactions"); var localizer = localization.localizer(); @@ -237,6 +277,9 @@ private void initInteractions() { .build(); } + /** + * Initializes the listeners for the bot. + */ private void initListener() { log.info("Setting up listener."); var localizer = localization.localizer(); @@ -261,10 +304,18 @@ private void initListener() { roleUpdater); } + /** + * Gets the shard manager. + * + * @return the shard manager + */ public ShardManager shardManager() { return shardManager; } + /** + * Shuts down the bot. + */ public void shutdown() { shardManager.shutdown(); } diff --git a/src/main/java/de/chojo/repbot/core/Data.java b/src/main/java/de/chojo/repbot/core/Data.java index 75c750677..9669a99dd 100644 --- a/src/main/java/de/chojo/repbot/core/Data.java +++ b/src/main/java/de/chojo/repbot/core/Data.java @@ -30,6 +30,9 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Manages the data connections and data access objects (DAOs) for the application. + */ public class Data { private static final Logger log = getLogger(Data.class); private final Threading threading; @@ -42,17 +45,38 @@ public class Data { private Voice voice; private Analyzer analyzer; + /** + * Constructs a new Data instance. + * + * @param threading the threading configuration + * @param configuration the application configuration + */ private Data(Threading threading, Configuration configuration) { this.threading = threading; this.configuration = configuration; } + /** + * Creates and initializes a new Data instance. + * + * @param threading the threading configuration + * @param configuration the application configuration + * @return the initialized Data instance + * @throws SQLException if a database access error occurs + * @throws IOException if an I/O error occurs + */ public static Data create(Threading threading, Configuration configuration) throws SQLException, IOException { var data = new Data(threading, configuration); data.init(); return data; } + /** + * Initializes the data connections and DAOs. + * + * @throws SQLException if a database access error occurs + * @throws IOException if an I/O error occurs + */ public void init() throws SQLException, IOException { initConnection(); configure(); @@ -60,6 +84,9 @@ public void init() throws SQLException, IOException { initDao(); } + /** + * Initializes the database connection. + */ public void initConnection() { try { dataSource = getConnectionPool(); @@ -73,6 +100,12 @@ public void initConnection() { } } + /** + * Updates the database schema to the latest version. + * + * @throws IOException if an I/O error occurs + * @throws SQLException if a database access error occurs + */ private void updateDatabase() throws IOException, SQLException { var schema = configuration.database().schema(); SqlUpdater.builder(dataSource, PostgreSql.get()) @@ -82,6 +115,9 @@ private void updateDatabase() throws IOException, SQLException { .execute(); } + /** + * Configures the query settings and row mappers. + */ private void configure() { log.info("Configuring Query Configuration"); var logger = getLogger("DbLogger"); @@ -95,6 +131,9 @@ private void configure() { .build()); } + /** + * Initializes the data access objects (DAOs). + */ private void initDao() { log.info("Creating DAOs"); guilds = new Guilds(configuration); @@ -105,6 +144,11 @@ private void initDao() { voice = new Voice(configuration); } + /** + * Creates a connection pool for the database. + * + * @return the HikariDataSource instance + */ private HikariDataSource getConnectionPool() { log.info("Creating connection pool."); var data = configuration.database(); @@ -122,30 +166,63 @@ private HikariDataSource getConnectionPool() { .build(); } + /** + * Retrieves the Guilds DAO. + * + * @return the Guilds DAO + */ public Guilds guilds() { return guilds; } + /** + * Retrieves the GDPR DAO. + * + * @return the GDPR DAO + */ public Gdpr gdpr() { return gdpr; } + /** + * Retrieves the Cleanup DAO. + * + * @return the Cleanup DAO + */ public Cleanup cleanup() { return cleanup; } + /** + * Retrieves the Metrics DAO. + * + * @return the Metrics DAO + */ public Metrics metrics() { return metrics; } + /** + * Retrieves the Voice DAO. + * + * @return the Voice DAO + */ public Voice voice() { return voice; } + /** + * Shuts down the data connections. + */ public void shutDown() { dataSource.close(); } + /** + * Retrieves the Analyzer DAO. + * + * @return the Analyzer DAO + */ public Analyzer analyzer() { return analyzer; } diff --git a/src/main/java/de/chojo/repbot/core/Localization.java b/src/main/java/de/chojo/repbot/core/Localization.java index 8e851d169..3d4eea9a8 100644 --- a/src/main/java/de/chojo/repbot/core/Localization.java +++ b/src/main/java/de/chojo/repbot/core/Localization.java @@ -8,20 +8,37 @@ import de.chojo.jdautil.localization.Localizer; import net.dv8tion.jda.api.interactions.DiscordLocale; +/** + * Manages localization settings and provides a Localizer instance. + */ public class Localization { private final Data data; private Localizer localizer; + /** + * Constructs a new Localization instance with the specified data. + * + * @param data the data provider + */ private Localization(Data data) { this.data = data; } + /** + * Creates and initializes a new Localization instance. + * + * @param data the data provider + * @return a new Localization instance + */ public static Localization create(Data data) { var localization = new Localization(data); localization.init(); return localization; } + /** + * Initializes the Localizer with supported languages and settings. + */ public void init() { localizer = Localizer.builder(DiscordLocale.ENGLISH_US) .addLanguage(DiscordLocale.GERMAN, @@ -34,6 +51,11 @@ public void init() { .build(); } + /** + * Returns the Localizer instance. + * + * @return the Localizer instance + */ public Localizer localizer() { return localizer; } diff --git a/src/main/java/de/chojo/repbot/core/Shutdown.java b/src/main/java/de/chojo/repbot/core/Shutdown.java index 6bb3c3c82..8a3cb62c7 100644 --- a/src/main/java/de/chojo/repbot/core/Shutdown.java +++ b/src/main/java/de/chojo/repbot/core/Shutdown.java @@ -10,28 +10,50 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Handles the shutdown process for the bot, including shutting down the shard manager, + * scheduler, and database connections. + */ public class Shutdown { private static final Logger log = getLogger(Shutdown.class); private final Bot bot; private final Threading threading; private final Data data; + /** + * Constructs a new Shutdown instance. + * + * @param bot the bot instance + * @param threading the threading instance + * @param data the data instance + */ private Shutdown(Bot bot, Threading threading, Data data) { this.bot = bot; this.threading = threading; this.data = data; } + /** + * Creates and initializes a new Shutdown instance. + * + * @param bot the bot instance + * @param threading the threading instance + * @param data the data instance + * @return the created Shutdown instance + */ public static Shutdown create(Bot bot, Threading threading, Data data) { var shutdown = new Shutdown(bot, threading, data); shutdown.init(); return shutdown; } + /** + * Initializes the shutdown hook to handle the shutdown process. + */ public void init() { log.info("Creating Shutdown Hook"); var shutdown = new Thread(() -> { - log.info("Shuting down shardmanager."); + log.info("Shutting down shard manager."); bot.shutdown(); log.info("Shutting down scheduler."); threading.shutdown(); diff --git a/src/main/java/de/chojo/repbot/core/Threading.java b/src/main/java/de/chojo/repbot/core/Threading.java index 7d9c3b9c8..03bdd8cce 100644 --- a/src/main/java/de/chojo/repbot/core/Threading.java +++ b/src/main/java/de/chojo/repbot/core/Threading.java @@ -15,17 +15,57 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Class for managing threading and executor services. + */ public class Threading { + /** + * Logger instance for logging events. + */ private static final Logger log = getLogger(Threading.class); + + /** + * Uncaught exception handler for logging uncaught exceptions. + */ private static final Thread.UncaughtExceptionHandler EXCEPTION_HANDLER = (t, e) -> log.error(LogNotify.NOTIFY_ADMIN, "An uncaught exception occured in " + t.getName() + "-" + t.getId() + ".", e); + + /** + * Thread group for event workers. + */ private final ThreadGroup eventGroup = new ThreadGroup("Event Worker"); + + /** + * Thread group for scheduled workers. + */ private final ThreadGroup workerGroup = new ThreadGroup("Scheduled Worker"); + + /** + * Thread group for Hikari workers. + */ private final ThreadGroup hikariGroup = new ThreadGroup("Hikari Worker"); + + /** + * Thread group for JDA workers. + */ private final ThreadGroup jdaGroup = new ThreadGroup("JDA Worker"); + + /** + * Executor service for event threads. + */ private final ExecutorService eventThreads = Executors.newFixedThreadPool(20, createThreadFactory(eventGroup)); + + /** + * Scheduled executor service for RepBot workers. + */ private final ScheduledExecutorService repBotWorker = Executors.newScheduledThreadPool(3, createThreadFactory(workerGroup)); + /** + * Creates a thread factory for the given thread group. + * + * @param group the thread group + * @return the thread factory + */ public static ThreadFactory createThreadFactory(ThreadGroup group) { return r -> { var thread = new Thread(group, r, group.getName()); @@ -34,30 +74,69 @@ public static ThreadFactory createThreadFactory(ThreadGroup group) { }; } + /** + * Creates a new threading instance. + */ + public Threading(){ + } + + /** + * Retrieves the event thread group. + * + * @return the event thread group + */ public ThreadGroup eventGroup() { return eventGroup; } + /** + * Retrieves the worker thread group. + * + * @return the worker thread group + */ public ThreadGroup workerGroup() { return workerGroup; } + /** + * Retrieves the Hikari thread group. + * + * @return the Hikari thread group + */ public ThreadGroup hikariGroup() { return hikariGroup; } + /** + * Retrieves the JDA thread group. + * + * @return the JDA thread group + */ public ThreadGroup jdaGroup() { return jdaGroup; } + /** + * Retrieves the event executor service. + * + * @return the event executor service + */ public ExecutorService eventThreads() { return eventThreads; } + /** + * Retrieves the scheduled executor service for RepBot workers. + * + * @return the scheduled executor service for RepBot workers + */ public ScheduledExecutorService repBotWorker() { return repBotWorker; } + /** + * Shuts down the scheduled executor service for RepBot workers. + */ public void shutdown() { repBotWorker.shutdown(); } diff --git a/src/main/java/de/chojo/repbot/core/Web.java b/src/main/java/de/chojo/repbot/core/Web.java index 77ed3dd70..446c6b83a 100644 --- a/src/main/java/de/chojo/repbot/core/Web.java +++ b/src/main/java/de/chojo/repbot/core/Web.java @@ -22,7 +22,13 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Class responsible for initializing and managing the web server and API. + */ public class Web { + /** + * Logger instance for logging events. + */ private static final Logger log = getLogger(Web.class); private final Bot bot; private final Data data; @@ -30,6 +36,14 @@ public class Web { private final Configuration configuration; private Javalin javalin; + /** + * Constructs a new Web instance. + * + * @param bot the bot instance + * @param data the data instance + * @param threading the threading instance + * @param configuration the configuration instance + */ private Web(Bot bot, Data data, Threading threading, Configuration configuration) { this.bot = bot; this.data = data; @@ -37,17 +51,32 @@ private Web(Bot bot, Data data, Threading threading, Configuration configuration this.configuration = configuration; } + /** + * Creates and initializes a new Web instance. + * + * @param bot the bot instance + * @param data the data instance + * @param threading the threading instance + * @param configuration the configuration instance + * @return the created Web instance + */ public static Web create(Bot bot, Data data, Threading threading, Configuration configuration) { var web = new Web(bot, data, threading, configuration); web.init(); return web; } + /** + * Initializes the web server and API. + */ public void init() { initApi(); initBotList(); } + /** + * Initializes the API with OpenAPI documentation. + */ private void initApi() { var api = configuration.api(); @@ -66,6 +95,9 @@ private void initApi() { new Api(javalin, data.metrics()).init(); } + /** + * Initializes the bot list services and vote handling. + */ private void initBotList() { var botlist = configuration.botlist(); if (!botlist.isSubmit()) return; diff --git a/src/main/java/de/chojo/repbot/dao/access/Analyzer.java b/src/main/java/de/chojo/repbot/dao/access/Analyzer.java index a16d09c05..beabb9ec1 100644 --- a/src/main/java/de/chojo/repbot/dao/access/Analyzer.java +++ b/src/main/java/de/chojo/repbot/dao/access/Analyzer.java @@ -13,14 +13,25 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static org.slf4j.LoggerFactory.getLogger; +/** + * Analyzer class responsible for cleaning up old analyzer and reputation results from the database. + */ public class Analyzer { private static final Logger log = getLogger(Analyzer.class); private final Configuration configuration; + /** + * Constructs a new Analyzer instance. + * + * @param configuration the configuration object containing cleanup settings + */ public Analyzer(Configuration configuration) { this.configuration = configuration; } + /** + * Cleans up old entries from the analyzer and reputation results tables based on the configured interval. + */ public void cleanup() { var delete = Query.query(""" DELETE FROM analyzer_results WHERE analyzed < now() - ?::INTERVAL; diff --git a/src/main/java/de/chojo/repbot/dao/access/Cleanup.java b/src/main/java/de/chojo/repbot/dao/access/Cleanup.java index 9b6d7d917..9d8cf1e2c 100644 --- a/src/main/java/de/chojo/repbot/dao/access/Cleanup.java +++ b/src/main/java/de/chojo/repbot/dao/access/Cleanup.java @@ -9,7 +9,22 @@ import java.util.List; +/** + * Class responsible for handling cleanup operations in the database. + */ public class Cleanup { + + /** + * Creates a new cleanup instance. + */ + public Cleanup(){ + } + + /** + * Retrieves a list of guild IDs that require cleanup. + * + * @return a list of guild IDs + */ public List getCleanupList() { return Query.query("SELECT guild_id FROM self_cleanup;") .single() diff --git a/src/main/java/de/chojo/repbot/dao/access/Gdpr.java b/src/main/java/de/chojo/repbot/dao/access/Gdpr.java index af7c88d0f..0c6c23955 100644 --- a/src/main/java/de/chojo/repbot/dao/access/Gdpr.java +++ b/src/main/java/de/chojo/repbot/dao/access/Gdpr.java @@ -19,14 +19,27 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static org.slf4j.LoggerFactory.getLogger; +/** + * Provides GDPR-related data access methods. + */ public class Gdpr { private static final Logger log = getLogger(Gdpr.class); private final Configuration configuration; + /** + * Constructs a new Gdpr instance. + * + * @param configuration the configuration object + */ public Gdpr(Configuration configuration) { this.configuration = configuration; } + /** + * Retrieves the list of removal tasks that are scheduled for deletion. + * + * @return the list of removal tasks + */ public List getRemovalTasks() { return Query.query(""" SELECT @@ -42,6 +55,9 @@ public List getRemovalTasks() { .all(); } + /** + * Cleans up GDPR requests that are older than the configured number of days. + */ public void cleanupRequests() { Query.query(""" DELETE FROM gdpr_log @@ -52,17 +68,22 @@ public void cleanupRequests() { .update(); } + /** + * Creates a new GDPR user request. + * + * @param user the user requesting their data + * @return the GDPR user request + */ public GdprUser request(User user) { return new GdprUser(user); } /** - * Get a list of {@link GdprUser}s which have requested their data. - *

- * Only users which are known to the provided shard manager will be returned. + * Retrieves a list of GDPR users who have requested their data. + * Only users known to the provided shard manager will be returned. * - * @param shardManager shardmanager to resolve users. - * @return list of users + * @param shardManager the shard manager to resolve users + * @return the list of GDPR users */ public List getReportRequests(ShardManager shardManager) { return Query @@ -70,7 +91,7 @@ public List getReportRequests(ShardManager shardManager) { SELECT user_id FROM gdpr_log WHERE received IS NULL - AND last_attempt < now() - (least(48, attempts) || ' HOURS')::INTERVAL + AND last_attempt < now() - (least(48, attempts) || ' HOURS')::INTERVAL """) .single() .map(rs -> GdprUser.build(rs, shardManager)) diff --git a/src/main/java/de/chojo/repbot/dao/access/gdpr/GdprUser.java b/src/main/java/de/chojo/repbot/dao/access/gdpr/GdprUser.java index 3a8eda4f9..05bedf3c1 100644 --- a/src/main/java/de/chojo/repbot/dao/access/gdpr/GdprUser.java +++ b/src/main/java/de/chojo/repbot/dao/access/gdpr/GdprUser.java @@ -25,15 +25,31 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; +/** + * Provides GDPR-related data access methods for users. + */ public class GdprUser { private static final Logger log = getLogger(GdprUser.class); private final User user; + /** + * Constructs a new GdprUser instance. + * + * @param user the User instance + */ public GdprUser(User user) { this.user = user; } + /** + * Builds a GdprUser instance from the given database row and shard manager. + * + * @param rs the database row + * @param shardManager the shard manager + * @return the GdprUser instance, or null if the user could not be retrieved + * @throws SQLException if a database access error occurs + */ @Nullable public static GdprUser build(Row rs, ShardManager shardManager) throws SQLException { try { @@ -50,6 +66,11 @@ public static GdprUser build(Row rs, ShardManager shardManager) throws SQLExcept } } + /** + * Queues the user for deletion by adding them to the cleanup schedule. + * + * @return true if the user was successfully queued for deletion, false otherwise + */ public boolean queueDeletion() { log.info("User {} requested deletion of their data", userId()); return query(""" @@ -64,6 +85,11 @@ ON CONFLICT(guild_id, user_id) .changed(); } + /** + * Requests the deletion of the user's data. + * + * @return true if the request was successful, false otherwise + */ public boolean request() { try (var conn = QueryConfiguration.getDefault().withSingleTransaction()) { var res = conn.query(""" @@ -85,18 +111,29 @@ ON CONFLICT(user_id) } } + /** + * Marks the user's GDPR request as sent. + */ public void requestSend() { query("UPDATE gdpr_log SET received = now(), last_attempt = now() WHERE user_id = ?") .single(call().bind(userId())) .update(); } + /** + * Marks the user's GDPR request as failed. + */ public void requestSendFailed() { query("UPDATE gdpr_log SET attempts = attempts + 1, last_attempt = now() WHERE user_id = ?") .single(call().bind(userId())) .update(); } + /** + * Retrieves the user's data. + * + * @return an Optional containing the user's data, or an empty Optional if the data could not be retrieved + */ public Optional userData() { return query("SELECT aggregate_user_data(?)") .single(call().bind(userId())) @@ -166,6 +203,11 @@ public boolean sendData() { return true; } + /** + * Retrieves the ID of the user associated with this instance. + * + * @return the user ID + */ private long userId() { return user.getIdLong(); } diff --git a/src/main/java/de/chojo/repbot/dao/access/gdpr/RemovalTask.java b/src/main/java/de/chojo/repbot/dao/access/gdpr/RemovalTask.java index 2c560e0d3..7f58d6ed4 100644 --- a/src/main/java/de/chojo/repbot/dao/access/gdpr/RemovalTask.java +++ b/src/main/java/de/chojo/repbot/dao/access/gdpr/RemovalTask.java @@ -15,26 +15,52 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static org.slf4j.LoggerFactory.getLogger; +/** + * Represents a task for removing user or guild data for GDPR compliance. + */ public final class RemovalTask { private static final Logger log = getLogger(RemovalTask.class); private final long taskId; private final long guildId; private final long userId; + /** + * Constructs a RemovalTask with the specified task ID, guild ID, and user ID. + * + * @param taskId the task ID + * @param guildId the guild ID + * @param userId the user ID + */ public RemovalTask(long taskId, long guildId, long userId) { this.taskId = taskId; this.guildId = guildId; this.userId = userId; } + /** + * Builds a RemovalTask from the given database row. + * + * @param rs the database row + * @return a new RemovalTask instance + * @throws SQLException if a database access error occurs + */ public static RemovalTask build(Row rs) throws SQLException { return new RemovalTask(rs.getLong("task_id"), rs.getLong("guild_id"), rs.getLong("user_id")); } + /** + * Executes an anonymous removal task for the specified guild ID and user ID. + * + * @param guildId the guild ID + * @param userId the user ID + */ public static void anonymExecute(long guildId, long userId) { new RemovalTask(-1L, guildId, userId).executeRemovalTask(); } + /** + * Executes the removal task, deleting user or guild data from the database. + */ public void executeRemovalTask() { try (var conn = QueryConfiguration.getDefault().withSingleTransaction()) { if (userId() == 0) { @@ -70,14 +96,29 @@ public void executeRemovalTask() { } } + /** + * Gets the task ID. + * + * @return the task ID + */ public long taskId() { return taskId; } + /** + * Gets the guild ID. + * + * @return the guild ID + */ public long guildId() { return guildId; } + /** + * Gets the user ID. + * + * @return the user ID + */ public long userId() { return userId; } diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/Cleanup.java b/src/main/java/de/chojo/repbot/dao/access/guild/Cleanup.java index fe47822d7..b07dd0188 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/Cleanup.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/Cleanup.java @@ -14,13 +14,24 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Class responsible for handling cleanup operations for a guild. + */ public class Cleanup implements GuildHolder { private final RepGuild repGuild; + /** + * Constructs a Cleanup instance with the specified RepGuild. + * + * @param repGuild the RepGuild instance + */ public Cleanup(RepGuild repGuild) { this.repGuild = repGuild; } + /** + * Prompts self-cleanup by inserting a record into the self_cleanup table. + */ public void selfCleanupPrompt() { query(""" INSERT INTO self_cleanup(guild_id) VALUES(?) @@ -29,6 +40,11 @@ INSERT INTO self_cleanup(guild_id) VALUES(?) .update(); } + /** + * Retrieves the time when the cleanup was prompted. + * + * @return an Optional containing the LocalDateTime of the prompt, if present + */ public Optional getCleanupPromptTime() { return query(""" SELECT prompted FROM self_cleanup WHERE guild_id = ? @@ -38,6 +54,9 @@ public Optional getCleanupPromptTime() { .first(); } + /** + * Marks the cleanup as done by deleting the record from the self_cleanup table. + */ public void cleanupDone() { query(""" DELETE FROM self_cleanup WHERE guild_id = ? @@ -46,11 +65,21 @@ public void cleanupDone() { .update(); } + /** + * Gets the Guild associated with this Cleanup instance. + * + * @return the Guild + */ @Override public Guild guild() { return repGuild.guild(); } + /** + * Gets the ID of the Guild associated with this Cleanup instance. + * + * @return the Guild ID + */ @Override public long guildId() { return repGuild.guildId(); diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/Gdpr.java b/src/main/java/de/chojo/repbot/dao/access/guild/Gdpr.java index d5f4d32e5..2e7f82e65 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/Gdpr.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/Gdpr.java @@ -13,24 +13,45 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; +/** + * Provides GDPR-related data access methods for guilds. + */ public class Gdpr implements GuildHolder { private final RepGuild repGuild; private static final Logger log = getLogger(Gdpr.class); + /** + * Constructs a new Gdpr instance. + * + * @param repGuild the RepGuild instance + */ public Gdpr(RepGuild repGuild) { this.repGuild = repGuild; } + /** + * Retrieves the guild associated with this instance. + * + * @return the guild + */ @Override public Guild guild() { return repGuild.guild(); } + /** + * Retrieves the ID of the guild associated with this instance. + * + * @return the guild ID + */ @Override public long guildId() { return repGuild.guildId(); } + /** + * Queues the guild for deletion by adding it to the cleanup schedule. + */ public void queueDeletion() { if (query(""" INSERT INTO @@ -46,6 +67,9 @@ ON CONFLICT(guild_id, user_id) } } + /** + * Dequeues the guild from deletion by removing it from the cleanup schedule. + */ public void dequeueDeletion() { if (query("DELETE FROM cleanup_schedule WHERE guild_id = ? AND user_id = 0;") .single(call().bind(guildId())) diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/RepGuild.java b/src/main/java/de/chojo/repbot/dao/access/guild/RepGuild.java index 916087574..6b2f47bf0 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/RepGuild.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/RepGuild.java @@ -21,6 +21,9 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Represents a guild with reputation and settings management. + */ public class RepGuild implements GuildHolder { private static final Cache CLEANUPS = CacheBuilder.newBuilder() .expireAfterAccess(2, TimeUnit.MINUTES).build(); @@ -31,6 +34,12 @@ public class RepGuild implements GuildHolder { private Guild guild; private final Configuration configuration; + /** + * Constructs a RepGuild with the specified guild and configuration. + * + * @param guild the guild + * @param configuration the configuration + */ public RepGuild(Guild guild, Configuration configuration) { super(); this.configuration = configuration; @@ -39,15 +48,30 @@ public RepGuild(Guild guild, Configuration configuration) { this.guild = guild; } + /** + * Returns the guild. + * + * @return the guild + */ public Guild guild() { return guild; } + /** + * Returns the guild ID. + * + * @return the guild ID + */ @Override public long guildId() { return guild.getIdLong(); } + /** + * Returns the GDPR settings for the guild. + * + * @return the GDPR settings + */ public Gdpr gdpr() { try { return GDPR.get(guildId(), () -> new Gdpr(this)); @@ -56,37 +80,41 @@ public Gdpr gdpr() { } } + /** + * Refreshes the guild with the specified guild. + * + * @param guild the guild + * @return the refreshed RepGuild + */ public RepGuild refresh(Guild guild) { this.guild = guild; return this; } - //Todo: We don't actually know how many users are on a guild and saved in the database. At some point we might want to add some pagination here. - /** - * A list of user ids of all users which are connected to this guild. + * Returns a list of user IDs of all users connected to this guild. * - * @return list of user ids + * @return list of user IDs */ public List userIds() { return query(""" SELECT - user_id AS user_id + user_id AS user_id FROM - ( - SELECT - donor_id AS user_id - FROM - reputation_log - WHERE guild_id = ? - UNION - DISTINCT - SELECT - receiver_id AS user_id - FROM - reputation_log - WHERE guild_id = ? - ) users + ( + SELECT + donor_id AS user_id + FROM + reputation_log + WHERE guild_id = ? + UNION + DISTINCT + SELECT + receiver_id AS user_id + FROM + reputation_log + WHERE guild_id = ? + ) users WHERE user_id != 0 """) .single(call().bind(guildId()).bind(guildId())) @@ -94,14 +122,29 @@ public List userIds() { .all(); } + /** + * Returns the reputation management for the guild. + * + * @return the reputation management + */ public Reputation reputation() { return reputation; } + /** + * Returns the settings for the guild. + * + * @return the settings + */ public Settings settings() { return settings; } + /** + * Returns the cleanup settings for the guild. + * + * @return the cleanup settings + */ public Cleanup cleanup() { try { return CLEANUPS.get(guildId(), () -> new Cleanup(this)); @@ -110,10 +153,20 @@ public Cleanup cleanup() { } } + /** + * Checks if the guild is identified by ID. + * + * @return true if the guild is identified by ID, false otherwise + */ public boolean isById() { return guild == null; } + /** + * Returns a string representation of the RepGuild. + * + * @return a string representation of the RepGuild + */ @Override public String toString() { return "RepGuild{" + @@ -121,12 +174,23 @@ public String toString() { '}'; } + /** + * Loads the guild using the specified shard manager. + * + * @param shardManager the shard manager + * @return the loaded RepGuild + */ public RepGuild load(ShardManager shardManager) { if (guild != null) return this; guild = shardManager.getGuildById(guildId()); return this; } + /** + * Returns the configuration for the guild. + * + * @return the configuration + */ public Configuration configuration() { return configuration; } diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/RepGuildId.java b/src/main/java/de/chojo/repbot/dao/access/guild/RepGuildId.java index 81511fc62..0d4e4379c 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/RepGuildId.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/RepGuildId.java @@ -9,14 +9,28 @@ import javax.sql.DataSource; +/** + * Represents a guild with a specific ID in the reputation bot. + */ public class RepGuildId extends RepGuild { private final long guildId; + /** + * Constructs a RepGuildId with the specified guild ID and configuration. + * + * @param guildId the ID of the guild + * @param configuration the configuration + */ public RepGuildId(long guildId, Configuration configuration) { super(null, configuration); this.guildId = guildId; } + /** + * Returns the ID of the guild. + * + * @return the guild ID + */ @Override public long guildId() { return guildId; diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/Reputation.java b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/Reputation.java index 12c586563..8673372cd 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/Reputation.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/Reputation.java @@ -28,15 +28,22 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; -public class Reputation implements GuildHolder { +/** + * Manages the reputation system for a guild. + */ +public class Reputation implements GuildHolder { private static final Logger log = getLogger(Reputation.class); private final RepGuild repGuild; - private final Ranking ranking; private final Cache users = CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES).build(); private final Log logAccess; private final Analyzer analyzer; + /** + * Constructs a Reputation object for the specified guild. + * + * @param repGuild the guild's reputation data access object + */ public Reputation(RepGuild repGuild) { this.repGuild = repGuild; ranking = new Ranking(this); @@ -44,24 +51,49 @@ public Reputation(RepGuild repGuild) { analyzer = new Analyzer(this); } + /** + * Returns the log access object for reputation logs. + * + * @return the log access object + */ public Log log() { return logAccess; } + /** + * Returns the analyzer object for reputation analysis. + * + * @return the analyzer object + */ public Analyzer analyzer() { return analyzer; } + /** + * Returns the guild associated with this reputation object. + * + * @return the guild + */ @Override public Guild guild() { return repGuild.guild(); } + /** + * Returns the guild ID associated with this reputation object. + * + * @return the guild ID + */ @Override public long guildId() { return repGuild().guildId(); } + /** + * Retrieves the reputation statistics for the guild. + * + * @return the guild reputation statistics + */ public GuildReputationStats stats() { return query("SELECT total_reputation, week_reputation, today_reputation, top_channel FROM get_guild_stats(?)") .single(call().bind(guildId())) @@ -74,6 +106,12 @@ public GuildReputationStats stats() { .orElseGet(() -> new GuildReputationStats(0, 0, 0, 0)); } + /** + * Retrieves the reputation user object for the specified member. + * + * @param member the guild member + * @return the reputation user object + */ public RepUser user(@NotNull Member member) { try { return users.get(member.getIdLong(), () -> new RepUser(this, member)).refresh(member); @@ -83,6 +121,12 @@ public RepUser user(@NotNull Member member) { } } + /** + * Retrieves the reputation user object for the specified user. + * + * @param user the user + * @return the reputation user object + */ public RepUser user(User user) { try { return users.get(user.getIdLong(), () -> new RepUser(this, user)); @@ -92,14 +136,29 @@ public RepUser user(User user) { } } + /** + * Returns the ranking object for reputation rankings. + * + * @return the ranking object + */ public Ranking ranking() { return ranking; } + /** + * Returns the guild's reputation data access object. + * + * @return the guild's reputation data access object + */ public RepGuild repGuild() { return repGuild; } + /** + * Returns the configuration object for the guild. + * + * @return the configuration object + */ public Configuration configuration() { return repGuild.configuration(); } diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Analyzer.java b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Analyzer.java index ffd94b47f..06d361695 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Analyzer.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Analyzer.java @@ -32,8 +32,15 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; +/** + * Class for analyzing and logging reputation-related data. + */ public class Analyzer implements GuildHolder { private static final Logger log = getLogger(Analyzer.class); + + /** + * ObjectMapper instance for JSON serialization and deserialization. + */ public static final ObjectMapper MAPPER = JsonMapper.builder() .configure(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS, true) .build() @@ -43,10 +50,22 @@ public class Analyzer implements GuildHolder { private final Reputation reputation; + /** + * Constructs an Analyzer with the specified Reputation instance. + * + * @param reputation the Reputation instance + */ public Analyzer(Reputation reputation) { this.reputation = reputation; } + /** + * Logs the analyzer result for a given message. + * + * @param message the message + * @param analyzerResult the analyzer result + * @return the analyzer result + */ public AnalyzerResult log(Message message, AnalyzerResult analyzerResult) { String resultString; try { @@ -67,6 +86,12 @@ ON CONFLICT (guild_id, message_id) return analyzerResult; } + /** + * Logs the submit result for a given message. + * + * @param message the message + * @param result the submit result + */ public void log(Message message, SubmitResult result) { String resultString; try { @@ -84,6 +109,12 @@ public void log(Message message, SubmitResult result) { .insert(); } + /** + * Retrieves the analyzer trace for a given message ID. + * + * @param messageId the message ID + * @return an optional containing the analyzer trace if found, otherwise empty + */ public Optional get(long messageId) { var resultEntry = getResults(messageId); @@ -94,7 +125,12 @@ public Optional get(long messageId) { return Optional.of(new AnalyzerTrace(resultEntry.orElse(null), submitResults)); } - + /** + * Retrieves the result entry for a given message ID. + * + * @param messageId the message ID + * @return an optional containing the result entry if found, otherwise empty + */ private Optional getResults(long messageId) { return query(""" SELECT guild_id, channel_id, message_id, result, analyzed @@ -114,6 +150,12 @@ private Optional getResults(long messageId) { }).first(); } + /** + * Retrieves the submit result entries for a given message ID. + * + * @param messageId the message ID + * @return a list of submit result entries + */ private List getSubmitResults(long messageId) { return query(""" SELECT guild_id, channel_id, message_id, result, submitted @@ -134,11 +176,21 @@ private List getSubmitResults(long messageId) { }).all(); } + /** + * Returns the guild associated with this analyzer. + * + * @return the guild + */ @Override public Guild guild() { return reputation.guild(); } + /** + * Returns the guild ID associated with this analyzer. + * + * @return the guild ID + */ @Override public long guildId() { return reputation.guildId(); diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Log.java b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Log.java index 1e7d11c03..8112b4251 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Log.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Log.java @@ -19,9 +19,17 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; -public class Log implements GuildHolder { +/** + * Handles logging of reputation-related actions for a guild. + */ +public class Log implements GuildHolder { private final Reputation reputation; + /** + * Constructs a new Log instance with the specified Reputation provider. + * + * @param reputation the Reputation provider + */ public Log(Reputation reputation) { this.reputation = reputation; } @@ -29,13 +37,21 @@ public Log(Reputation reputation) { /** * Get the last log entries for reputation received by the user. * - * @param user user - * @return sorted list of entries. the most recent first. + * @param user the user + * @param pageSize the number of entries per page + * @return a ReputationLogAccess object for paginated access to the log entries */ public ReputationLogAccess getUserReceivedLog(User user, int pageSize) { return new ReputationLogAccess(() -> getUserReceivedLogPages(user, pageSize), page -> getUserReceivedLogPage(user, pageSize, page)); } + /** + * Get the last log entries for reputation donated by the user. + * + * @param user the user + * @param pageSize the number of entries per page + * @return a ReputationLogAccess object for paginated access to the log entries + */ public ReputationLogAccess userDonatedLog(User user, int pageSize) { return new ReputationLogAccess(() -> getUserDonatedLogPages(user, pageSize), page -> getUserDonatedLogPage(user, pageSize, page)); } @@ -43,8 +59,10 @@ public ReputationLogAccess userDonatedLog(User user, int pageSize) { /** * Get the last log entries for reputation received by the user. * - * @param user user - * @return sorted list of entries. the most recent first. + * @param user the user + * @param pageSize the number of entries per page + * @param page the page number + * @return a list of ReputationLogEntry objects */ private List getUserReceivedLogPage(User user, int pageSize, int page) { return getLog("receiver_id", user.getIdLong(), pageSize, page); @@ -53,23 +71,35 @@ private List getUserReceivedLogPage(User user, int pageSize, /** * Get the last log entries for reputation donated by the user. * - * @param user user - * @return sorted list of entries. the most recent first. + * @param user the user + * @param pageSize the number of entries per page + * @param page the page number + * @return a list of ReputationLogEntry objects */ private List getUserDonatedLogPage(User user, int pageSize, int page) { return getLog("donor_id", user.getIdLong(), pageSize, page); } /** - * Get the log entried for a message + * Get the log entries for a message. * - * @param messageId message id - * @return sorted list of entries. the most recent first. + * @param messageId the message id + * @param count the number of entries to retrieve + * @return a list of ReputationLogEntry objects */ public List messageLog(long messageId, int count) { return getLog("message_id", messageId, count, 0); } + /** + * Get the log entries based on the specified column and id. + * + * @param column the column name to filter by + * @param id the id to filter by + * @param pageSize the number of entries per page + * @param page the page number + * @return a list of ReputationLogEntry objects + */ private List getLog(String column, long id, int pageSize, int page) { return query(""" SELECT @@ -95,6 +125,11 @@ private List getLog(String column, long id, int pageSize, in .all(); } + /** + * Get the latest reputation log entry. + * + * @return an Optional containing the latest ReputationLogEntry if found + */ public Optional getLatestReputation() { return query(""" SELECT @@ -118,8 +153,8 @@ public Optional getLatestReputation() { /** * Get the first log entry for a message. * - * @param message message id - * @return a log entry if found + * @param message the message id + * @return an Optional containing the ReputationLogEntry if found */ public Optional getLogEntry(long message) { return query(""" @@ -144,23 +179,45 @@ public Optional getLogEntry(long message) { } /** - * Get the log entries for a message. + * Get the log entry for a message. * - * @param message message - * @return a log entry if found + * @param message the message + * @return an Optional containing the ReputationLogEntry if found */ public Optional getLogEntry(Message message) { return getLogEntry(message.getIdLong()); } + /** + * Get the number of pages for the log entries donated by the user. + * + * @param user the user + * @param pageSize the number of entries per page + * @return the number of pages + */ private int getUserDonatedLogPages(User user, int pageSize) { return getLogPages("donor_id", user.getIdLong(), pageSize); } + /** + * Get the number of pages for the log entries received by the user. + * + * @param user the user + * @param pageSize the number of entries per page + * @return the number of pages + */ private int getUserReceivedLogPages(User user, int pageSize) { return getLogPages("receiver_id", user.getIdLong(), pageSize); } + /** + * Get the number of pages for the log entries based on the specified column and id. + * + * @param column the column name to filter by + * @param id the id to filter by + * @param pageSize the number of entries per page + * @return the number of pages + */ private int getLogPages(String column, long id, int pageSize) { return query(""" SELECT @@ -176,11 +233,21 @@ private int getLogPages(String column, long id, int pageSize) { .orElse(1); } + /** + * Returns the guild associated with this log. + * + * @return the guild + */ @Override public Guild guild() { return reputation.guild(); } + /** + * Returns the guild id associated with this log. + * + * @return the guild id + */ @Override public long guildId() { return reputation.guildId(); diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Ranking.java b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Ranking.java index 6b582350c..a77d763cd 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Ranking.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/Ranking.java @@ -17,33 +17,78 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Manages the ranking of users based on their reputation in a guild. + */ public class Ranking implements GuildHolder { private final Reputation reputation; + /** + * Constructs a Ranking instance with the specified Reputation instance. + * + * @param reputation the Reputation instance + */ public Ranking(Reputation reputation) { this.reputation = reputation; } + /** + * Gets the total number of ranking pages. + * + * @param pageSize the size of a page + * @return the total number of ranking pages + */ private int getRankingPageCount(int pageSize) { return pages(pageSize, "user_reputation"); } + /** + * Gets the total number of 7-day ranking pages. + * + * @param pageSize the size of a page + * @return the total number of 7-day ranking pages + */ private Integer get7DaysRankingPageCount(int pageSize) { return pages(pageSize, "user_reputation_7_days"); } + /** + * Gets the total number of 30-day ranking pages. + * + * @param pageSize the size of a page + * @return the total number of 30-day ranking pages + */ private Integer get30DaysRankingPageCount(int pageSize) { return pages(pageSize, "user_reputation_30_days"); } + /** + * Gets the total number of weekly ranking pages. + * + * @param pageSize the size of a page + * @return the total number of weekly ranking pages + */ private Integer getWeekRankingPageCount(int pageSize) { return pages(pageSize, "user_reputation_week"); } + /** + * Gets the total number of monthly ranking pages. + * + * @param pageSize the size of a page + * @return the total number of monthly ranking pages + */ private Integer getMonthRankingPageCount(int pageSize) { return pages(pageSize, "user_reputation_month"); } + /** + * Calculates the number of pages for a given table. + * + * @param pageSize the size of a page + * @param table the table name + * @return the number of pages + */ private Integer pages(int pageSize, String table) { return query(""" SELECT @@ -59,10 +104,23 @@ private Integer pages(int pageSize, String table) { .orElse(1); } + /** + * Gets the default ranking of the guild based on the reputation mode. + * + * @param pageSize the size of a page + * @return the default ranking of the guild + */ public GuildRanking defaultRanking(int pageSize) { return byMode(reputation.repGuild().settings().general().reputationMode(), pageSize); } + /** + * Gets the ranking of the guild based on the specified reputation mode. + * + * @param mode the reputation mode + * @param pageSize the size of a page + * @return the ranking of the guild + */ public GuildRanking byMode(ReputationMode mode, int pageSize) { return switch (mode) { case TOTAL -> total(pageSize); @@ -70,12 +128,12 @@ public GuildRanking byMode(ReputationMode mode, int pageSize) { case ROLLING_MONTH -> days30(pageSize); case WEEK -> week(pageSize); case MONTH -> month(pageSize); - default -> throw new IllegalArgumentException("Unkown input " + mode); + default -> throw new IllegalArgumentException("Unknown input " + mode); }; } /** - * Get the ranking of the guild. + * Gets the total ranking of the guild. * * @param pageSize the size of a page * @return a sorted list of reputation users @@ -85,7 +143,7 @@ public GuildRanking total(int pageSize) { } /** - * Get the 7 days ranking of the guild. + * Gets the 7-day ranking of the guild. * * @param pageSize the size of a page * @return a sorted list of reputation users @@ -95,7 +153,7 @@ public GuildRanking days7(int pageSize) { } /** - * Get the 30 days ranking of the guild. + * Gets the 30-day ranking of the guild. * * @param pageSize the size of a page * @return a sorted list of reputation users @@ -105,7 +163,7 @@ public GuildRanking days30(int pageSize) { } /** - * Get the weekly ranking of the guild. + * Gets the weekly ranking of the guild. * * @param pageSize the size of a page * @return a sorted list of reputation users @@ -115,7 +173,7 @@ public GuildRanking week(int pageSize) { } /** - * Get the monthly ranking of the guild. + * Gets the monthly ranking of the guild. * * @param pageSize the size of a page * @return a sorted list of reputation users @@ -125,32 +183,68 @@ public GuildRanking month(int pageSize) { } /** - * Get the ranking of the guild. + * Gets the ranking of the guild. * * @param pageSize the size of a page - * @param page the number of the page. zero based + * @param page the number of the page (zero-based) * @return a sorted list of reputation users */ private List getRankingPage(int pageSize, int page) { return getRankingPage(pageSize, page, "user_reputation"); } + /** + * Gets the 7-day ranking page of the guild. + * + * @param pageSize the size of a page + * @param page the number of the page (zero-based) + * @return a sorted list of reputation users + */ private List get7DaysRankingPage(int pageSize, int page) { return getRankingPage(pageSize, page, "user_reputation_7_days"); } + /** + * Gets the 30-day ranking page of the guild. + * + * @param pageSize the size of a page + * @param page the number of the page (zero-based) + * @return a sorted list of reputation users + */ private List get30DaysRankingPage(int pageSize, int page) { return getRankingPage(pageSize, page, "user_reputation_30_days"); } + /** + * Gets the weekly ranking page of the guild. + * + * @param pageSize the size of a page + * @param page the number of the page (zero-based) + * @return a sorted list of reputation users + */ private List getWeekRankingPage(int pageSize, int page) { return getRankingPage(pageSize, page, "user_reputation_week"); } + /** + * Gets the monthly ranking page of the guild. + * + * @param pageSize the size of a page + * @param page the number of the page (zero-based) + * @return a sorted list of reputation users + */ private List getMonthRankingPage(int pageSize, int page) { return getRankingPage(pageSize, page, "user_reputation_month"); } + /** + * Gets the ranking page of the guild for the specified table. + * + * @param pageSize the size of a page + * @param page the number of the page (zero-based) + * @param table the table name + * @return a sorted list of reputation users + */ private List getRankingPage(int pageSize, int page, String table) { return query(""" SELECT @@ -170,11 +264,21 @@ private List getRankingPage(int pageSize, int page, String table) { .all(); } + /** + * Retrieves the guild associated with this instance. + * + * @return the guild + */ @Override public Guild guild() { return reputation.guild(); } + /** + * Retrieves the guild ID associated with this instance. + * + * @return the guild ID + */ @Override public long guildId() { return reputation.guildId(); diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/RepUser.java b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/RepUser.java index 418176670..cd625a1ce 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/RepUser.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/RepUser.java @@ -9,7 +9,6 @@ import de.chojo.repbot.config.Configuration; import de.chojo.repbot.dao.access.guild.reputation.Reputation; import de.chojo.repbot.dao.access.guild.reputation.sub.user.Gdpr; -import de.chojo.repbot.dao.access.guild.settings.sub.AbuseProtection; import de.chojo.repbot.dao.components.MemberHolder; import de.chojo.repbot.dao.snapshots.RepProfile; import net.dv8tion.jda.api.entities.Guild; @@ -30,6 +29,9 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; +/** + * Represents a user with reputation in a guild. + */ public class RepUser implements MemberHolder { private static final Logger log = getLogger(RepUser.class); private final Reputation reputation; @@ -37,6 +39,12 @@ public class RepUser implements MemberHolder { private final User user; private Member member; + /** + * Constructs a RepUser with the specified reputation and member. + * + * @param reputation the reputation + * @param member the member + */ public RepUser(Reputation reputation, Member member) { gdpr = new Gdpr(this); this.reputation = reputation; @@ -44,21 +52,32 @@ public RepUser(Reputation reputation, Member member) { user = member.getUser(); } + /** + * Constructs a RepUser with the specified reputation and user. + * + * @param reputation the reputation + * @param user the user + */ public RepUser(Reputation reputation, User user) { gdpr = new Gdpr(this); this.reputation = reputation; this.user = user; } + /** + * Returns the GDPR settings for the user. + * + * @return the GDPR settings + */ public Gdpr gdpr() { return gdpr; } /** - * Add an amount of reputation to the reputation count of the user + * Adds an amount of reputation to the user's reputation count. * - * @param amount amount to add. Can be negative to subtract. - * @return true if added + * @param amount the amount to add, can be negative to subtract + * @return true if the reputation was added */ public boolean addReputation(long amount) { return query(""" @@ -70,20 +89,20 @@ INSERT INTO reputation_offset(guild_id, user_id, amount) VALUES (?,?,?) } /** - * Removes an amount of reputation from the reputation count of the user. + * Removes an amount of reputation from the user's reputation count. * - * @param amount amount to remove - * @return true if changed + * @param amount the amount to remove + * @return true if the reputation was removed */ public boolean removeReputation(long amount) { return addReputation(-amount); } /** - * Set the reputation offset to a value which will let the reputation of the user result in the entered amount. + * Sets the reputation offset to a value which will result in the specified reputation amount for the user. * * @param amount the reputation amount the user should have - * @return true if changed. + * @return true if the reputation was set */ public boolean setReputation(long amount) { var offset = amount - profile().reputation(); @@ -96,13 +115,13 @@ INSERT INTO reputation_offset(guild_id, user_id, amount) VALUES (?,?,?) } /** - * Log reputation for a user. + * Logs reputation for a user. * - * @param donor donator of the reputation - * @param message message to log - * @param refMessage reference message if available - * @param type type of reputation - * @return true if the repuation was logged. + * @param donor the donor of the reputation + * @param message the message to log + * @param refMessage the reference message if available + * @param type the type of reputation + * @return true if the reputation was logged */ public boolean addReputation(@Nullable Member donor, @NotNull Message message, @Nullable Message refMessage, ThankType type) { var success = query(""" @@ -119,21 +138,19 @@ ON CONFLICT(guild_id, donor_id, receiver_id, message_id) .insert() .changed(); if (success) { - log.debug("{} received one reputation from {} on guild {} for message {}", userId(), donor != null ? donor.getIdLong() : "unkown", guildId(), message.getIdLong()); + log.debug("{} received one reputation from {} on guild {} for message {}", userId(), donor != null ? donor.getIdLong() : "unknown", guildId(), message.getIdLong()); } return success; } /** - * Log reputation for a user. - *

- * The received date will be dated back to {@link Message#getTimeCreated()}. + * Logs reputation for a user with a backdated received date. * - * @param donor donator of the reputation - * @param message message to log - * @param refMessage reference message if available - * @param type type of reputation - * @return true if the repuation was logged. + * @param donor the donor of the reputation + * @param message the message to log + * @param refMessage the reference message if available + * @param type the type of reputation + * @return true if the reputation was logged */ public boolean addOldReputation(@Nullable Member donor, @NotNull Message message, @Nullable Message refMessage, ThankType type) { var success = query(""" @@ -153,17 +170,16 @@ ON CONFLICT(guild_id, donor_id, receiver_id, message_id) .insert() .changed(); if (success) { - log.debug("{} received one reputation from {} for message {}", user().getName(), donor != null ? donor.getEffectiveName() : "unkown", message.getIdLong()); + log.debug("{} received one reputation from {} for message {}", user().getName(), donor != null ? donor.getEffectiveName() : "unknown", message.getIdLong()); } return success; } - /** - * Get the last time the user gave reputation to the user or received reputation from this user + * Gets the last time the user gave or received reputation from another user. * * @param other the other user - * @return last timestamp as instant + * @return the last timestamp as an instant */ public Optional getLastReputation(Member other) { return @@ -189,10 +205,10 @@ public Optional getLastReputation(Member other) { } /** - * Get the time since the last reputation. + * Gets the time since the last reputation interaction with another user. * - * @param other receiver - * @return the time since the last vote in the requested time unit or 1 year if no entry was found. + * @param other the other user + * @return the duration since the last interaction or 1 year if no entry was found */ public Duration getLastRatedDuration(Member other) { return getLastReputation(other).map(last -> Duration.between(last, Instant.now())) @@ -200,9 +216,9 @@ public Duration getLastRatedDuration(Member other) { } /** - * Get the reputation user. + * Gets the reputation profile of the user. * - * @return the reputation user + * @return the reputation profile */ public RepProfile profile() { var mode = reputation.repGuild().settings().general().reputationMode(); @@ -232,9 +248,9 @@ public RepProfile profile() { } /** - * Get the amount of received reputation based on {@link AbuseProtection#maxReceivedHours()} + * Gets the amount of received reputation based on the maximum received hours. * - * @return amount of received reputation + * @return the amount of received reputation */ public int countReceived() { var hours = reputation().repGuild().settings().abuseProtection().maxReceivedHours(); @@ -246,9 +262,9 @@ public int countReceived() { } /** - * Get the amount of received reputation based on {@link AbuseProtection#maxGivenHours()} + * Gets the amount of given reputation based on the maximum given hours. * - * @return amount of given reputation + * @return the amount of given reputation */ public int countGiven() { var hours = reputation().repGuild().settings().abuseProtection().maxGivenHours(); @@ -259,30 +275,61 @@ public int countGiven() { .orElse(0); } + /** + * Returns the member associated with this RepUser. + * + * @return the member + */ @Override public Member member() { return member; } + /** + * Returns the user associated with this RepUser. + * + * @return the user + */ @Override public User user() { return user; } + /** + * Returns the guild associated with this RepUser. + * + * @return the guild + */ @Override public Guild guild() { return reputation.guild(); } + /** + * Refreshes the member associated with this RepUser. + * + * @param member the member + * @return the refreshed RepUser + */ public RepUser refresh(Member member) { this.member = member; return this; } + /** + * Returns the reputation associated with this RepUser. + * + * @return the reputation + */ public Reputation reputation() { return reputation; } + /** + * Returns the configuration associated with this RepUser. + * + * @return the configuration + */ public Configuration configuration() { return reputation.configuration(); } diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/user/Gdpr.java b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/user/Gdpr.java index 77f62660b..913f0d44d 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/user/Gdpr.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/reputation/sub/user/Gdpr.java @@ -16,19 +16,35 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; +/** + * Provides GDPR-related data access methods for users. + */ public class Gdpr implements MemberHolder { private final RepUser repUser; private static final Logger log = getLogger(Gdpr.class); + /** + * Constructs a new Gdpr instance. + * + * @param repUser the RepUser instance + */ public Gdpr(RepUser repUser) { this.repUser = repUser; } + /** + * Retrieves the member associated with this instance. + * + * @return the member + */ @Override public Member member() { return repUser.member(); } + /** + * Queues the user for deletion by adding them to the cleanup schedule. + */ public void queueDeletion() { log.info("User {} is scheduled for deletion on guild {}", userId(), guildId()); query(""" @@ -44,6 +60,9 @@ ON CONFLICT(guild_id, user_id) .update(); } + /** + * Dequeues the user from deletion by removing them from the cleanup schedule. + */ public void dequeueDeletion() { if (query(""" DELETE FROM @@ -58,11 +77,21 @@ public void dequeueDeletion() { } } + /** + * Retrieves the user associated with this instance. + * + * @return the user + */ @Override public User user() { return repUser.user(); } + /** + * Retrieves the guild associated with this instance. + * + * @return the guild + */ @Override public Guild guild() { return repUser.guild(); diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/Settings.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/Settings.java index 8a6b58afb..76e56e299 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/Settings.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/Settings.java @@ -19,6 +19,10 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Class representing the settings for a guild. + * Provides access to various configuration settings such as abuse protection, general settings, reputation settings, etc. + */ public class Settings implements GuildHolder { private final RepGuild repGuild; private AbuseProtection abuseProtection; @@ -29,10 +33,20 @@ public class Settings implements GuildHolder { private Announcements announcements; private Messages messages; + /** + * Constructs a new Settings object for the specified guild. + * + * @param repGuild the guild for which the settings are being managed + */ public Settings(RepGuild repGuild) { this.repGuild = repGuild; } + /** + * Retrieves the abuse protection settings for the guild. + * + * @return the abuse protection settings + */ public AbuseProtection abuseProtection() { if (abuseProtection != null) { return abuseProtection; @@ -60,6 +74,11 @@ public AbuseProtection abuseProtection() { return abuseProtection; } + /** + * Retrieves the announcements settings for the guild. + * + * @return the announcements settings + */ public Announcements announcements() { if (announcements != null) { return announcements; @@ -80,6 +99,11 @@ public Announcements announcements() { return announcements; } + /** + * Retrieves the reputation settings for the guild. + * + * @return the reputation settings + */ public Reputation reputation() { if (reputation != null) { return reputation; @@ -103,6 +127,11 @@ public Reputation reputation() { return reputation; } + /** + * Retrieves the general settings for the guild. + * + * @return the general settings + */ public General general() { if (general != null) { return general; @@ -125,6 +154,11 @@ public General general() { return general; } + /** + * Retrieves the thanking settings for the guild. + * + * @return the thanking settings + */ public Thanking thanking() { if (thanking != null) { return thanking; @@ -144,6 +178,11 @@ public Thanking thanking() { return thanking; } + /** + * Retrieves the messages settings for the guild. + * + * @return the messages settings + */ public Messages messages() { if (messages != null) { return messages; @@ -162,6 +201,11 @@ public Messages messages() { return messages; } + /** + * Retrieves the ranks settings for the guild. + * + * @return the ranks settings + */ public Ranks ranks() { if (ranks != null) { return ranks; @@ -170,15 +214,30 @@ public Ranks ranks() { return ranks; } + /** + * Retrieves the RepGuild object associated with this settings. + * + * @return the RepGuild object + */ public RepGuild repGuild() { return repGuild; } + /** + * Retrieves the Guild object associated with this settings. + * + * @return the Guild object + */ @Override public Guild guild() { return repGuild.guild(); } + /** + * Retrieves the guild ID associated with this settings. + * + * @return the guild ID + */ @Override public long guildId() { return repGuild.guildId(); diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/AbuseProtection.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/AbuseProtection.java index 26cb0731c..df94e285b 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/AbuseProtection.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/AbuseProtection.java @@ -21,6 +21,9 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Handles abuse protection settings for a guild. + */ public class AbuseProtection implements GuildHolder { private final Settings settings; private int cooldown; @@ -34,6 +37,21 @@ public class AbuseProtection implements GuildHolder { private int maxReceivedHours; private int maxMessageReputation; + /** + * Constructs an AbuseProtection object with specified settings. + * + * @param settings the settings + * @param cooldown the cooldown period + * @param maxMessageAge the maximum age of messages + * @param minMessages the minimum number of messages + * @param donorContext whether donor context is enabled + * @param receiverContext whether receiver context is enabled + * @param maxGiven the maximum given reputation + * @param maxGivenHours the hours for max given reputation + * @param maxReceived the maximum received reputation + * @param maxReceivedHours the hours for max received reputation + * @param maxMessageReputation the maximum reputation per message + */ public AbuseProtection(Settings settings, int cooldown, int maxMessageAge, int minMessages, boolean donorContext, boolean receiverContext, int maxGiven, int maxGivenHours, int maxReceived, int maxReceivedHours, int maxMessageReputation) { this.settings = settings; @@ -49,10 +67,23 @@ public AbuseProtection(Settings settings, int cooldown, int maxMessageAge, int m this.maxMessageReputation = maxMessageReputation; } + /** + * Constructs an AbuseProtection object with default settings. + * + * @param settings the settings + */ public AbuseProtection(Settings settings) { this(settings, 30, 30, 10, true, true, 0, 1, 0, 1, 3); } + /** + * Builds an AbuseProtection object from the database row. + * + * @param settings the settings + * @param rs the database row + * @return the AbuseProtection object + * @throws SQLException if a database access error occurs + */ public static AbuseProtection build(Settings settings, Row rs) throws SQLException { return new AbuseProtection(settings, rs.getInt("cooldown"), @@ -67,46 +98,102 @@ public static AbuseProtection build(Settings settings, Row rs) throws SQLExcepti rs.getInt("max_message_reputation")); } + /** + * Gets the cooldown period. + * + * @return the cooldown period + */ public int cooldown() { return cooldown; } + /** + * Gets the maximum age of messages. + * + * @return the maximum age of messages + */ public int maxMessageAge() { return maxMessageAge; } + /** + * Gets the minimum number of messages. + * + * @return the minimum number of messages + */ public int minMessages() { return minMessages; } + /** + * Gets the maximum reputation per message. + * + * @return the maximum reputation per message + */ public int maxMessageReputation() { return maxMessageReputation; } + /** + * Checks if donor context is enabled. + * + * @return true if donor context is enabled, false otherwise + */ public boolean isDonorContext() { return donorContext; } + /** + * Checks if receiver context is enabled. + * + * @return true if receiver context is enabled, false otherwise + */ public boolean isReceiverContext() { return receiverContext; } + /** + * Gets the maximum given reputation. + * + * @return the maximum given reputation + */ public int maxGiven() { return maxGiven; } + /** + * Gets the hours for max given reputation. + * + * @return the hours for max given reputation + */ public int maxGivenHours() { return maxGivenHours; } + /** + * Gets the maximum received reputation. + * + * @return the maximum received reputation + */ public int maxReceived() { return maxReceived; } + /** + * Gets the hours for max received reputation. + * + * @return the hours for max received reputation + */ public int maxReceivedHours() { return maxReceivedHours; } + /** + * Sets the cooldown period. + * + * @param cooldown the cooldown period + * @return the updated cooldown period + */ public int cooldown(int cooldown) { if (set("cooldown", stmt -> stmt.bind(cooldown))) { this.cooldown = cooldown; @@ -114,6 +201,12 @@ public int cooldown(int cooldown) { return this.cooldown; } + /** + * Sets the maximum age of messages. + * + * @param maxMessageAge the maximum age of messages + * @return the updated maximum age of messages + */ public int maxMessageAge(int maxMessageAge) { if (set("max_message_age", stmt -> stmt.bind(maxMessageAge))) { this.maxMessageAge = maxMessageAge; @@ -121,6 +214,12 @@ public int maxMessageAge(int maxMessageAge) { return this.maxMessageAge; } + /** + * Sets the minimum number of messages. + * + * @param minMessages the minimum number of messages + * @return the updated minimum number of messages + */ public int minMessages(int minMessages) { if (set("min_messages", stmt -> stmt.bind(minMessages))) { this.minMessages = minMessages; @@ -128,6 +227,12 @@ public int minMessages(int minMessages) { return this.minMessages; } + /** + * Sets whether donor context is enabled. + * + * @param donorContext the donor context status + * @return the updated donor context status + */ public boolean donorContext(boolean donorContext) { if (set("donor_context", stmt -> stmt.bind(donorContext))) { this.donorContext = donorContext; @@ -135,6 +240,12 @@ public boolean donorContext(boolean donorContext) { return this.donorContext; } + /** + * Sets whether receiver context is enabled. + * + * @param receiverContext the receiver context status + * @return the updated receiver context status + */ public boolean receiverContext(boolean receiverContext) { if (set("receiver_context", stmt -> stmt.bind(receiverContext))) { this.receiverContext = receiverContext; @@ -142,6 +253,12 @@ public boolean receiverContext(boolean receiverContext) { return this.receiverContext; } + /** + * Sets the maximum given reputation. + * + * @param maxGiven the maximum given reputation + * @return the updated maximum given reputation + */ public int maxGiven(int maxGiven) { var result = set("max_given", stmt -> stmt.bind(Math.max(maxGiven, 0))); if (result) { @@ -150,6 +267,12 @@ public int maxGiven(int maxGiven) { return this.maxGiven; } + /** + * Sets the hours for max given reputation. + * + * @param maxGivenHours the hours for max given reputation + * @return the updated hours for max given reputation + */ public int maxGivenHours(int maxGivenHours) { var result = set("max_given_hours", stmt -> stmt.bind(Math.max(maxGivenHours, 1))); if (result) { @@ -158,6 +281,12 @@ public int maxGivenHours(int maxGivenHours) { return this.maxGivenHours; } + /** + * Sets the maximum received reputation. + * + * @param maxReceived the maximum received reputation + * @return the updated maximum received reputation + */ public int maxReceived(int maxReceived) { var result = set("max_received", stmt -> stmt.bind(Math.max(maxReceived, 0))); if (result) { @@ -166,6 +295,12 @@ public int maxReceived(int maxReceived) { return this.maxReceived; } + /** + * Sets the hours for max received reputation. + * + * @param maxReceivedHours the hours for max received reputation + * @return the updated hours for max received reputation + */ public int maxReceivedHours(int maxReceivedHours) { var result = set("max_received_hours", stmt -> stmt.bind(Math.max(maxReceivedHours, 1))); if (result) { @@ -174,6 +309,12 @@ public int maxReceivedHours(int maxReceivedHours) { return this.maxReceivedHours; } + /** + * Sets the maximum reputation per message. + * + * @param maxMessageReputation the maximum reputation per message + * @return the updated maximum reputation per message + */ public int maxMessageReputation(int maxMessageReputation) { if (set("max_message_reputation", stmt -> stmt.bind(maxMessageReputation))) { this.maxMessageReputation = maxMessageReputation; @@ -181,6 +322,12 @@ public int maxMessageReputation(int maxMessageReputation) { return this.maxMessageReputation; } + /** + * Checks if a message is older than the maximum message age. + * + * @param message the message to check + * @return true if the message is older than the maximum message age, false otherwise + */ public boolean isOldMessage(Message message) { if (maxMessageAge == 0) return false; var until = message.getTimeCreated().toInstant().until(Instant.now(), ChronoUnit.MINUTES); @@ -188,7 +335,7 @@ public boolean isOldMessage(Message message) { } /** - * Checks if the member has reached the {@link #maxGiven} amount of reputation in the last {@link #maxGivenHours}. + * Checks if the member has reached the max given reputation in the last max given hours. * * @param member member to check * @return true if the limit is reached @@ -199,7 +346,7 @@ public boolean isDonorLimit(Member member) { } /** - * Checks if the member has reached the {@link #maxReceived} amount of reputation in the last {@link #maxReceivedHours}. + * Checks if the member has reached the max received reputation in the last max received hours. * * @param member member to check * @return true if the limit is reached @@ -209,14 +356,31 @@ public boolean isReceiverLimit(Member member) { return settings.repGuild().reputation().user(member).countReceived() >= maxReceived; } + /** + * Checks if the donor limit is enabled. + * + * @return true if the donor limit is enabled, false otherwise + */ public boolean isDonorLimit() { return maxGiven != 0; } + /** + * Checks if the receiver limit is enabled. + * + * @return true if the receiver limit is enabled, false otherwise + */ public boolean isReceiverLimit() { return maxReceived != 0; } + /** + * Sets a parameter in the database. + * + * @param parameter the parameter to set + * @param builder the function to build the call + * @return true if the parameter was set successfully, false otherwise + */ private boolean set(String parameter, Function builder) { return query(""" INSERT INTO abuse_protection(guild_id, %s) VALUES (?, ?) @@ -228,28 +392,43 @@ ON CONFLICT(guild_id) .changed(); } + /** + * Gets the guild associated with the settings. + * + * @return the guild + */ @Override public Guild guild() { return settings.guild(); } + /** + * Gets the ID of the guild associated with the settings. + * + * @return the guild ID + */ @Override public long guildId() { return settings.guildId(); } + /** + * Returns a pretty string representation of the abuse protection settings. + * + * @return the pretty string + */ public String prettyString() { return """ **Context** Donor: %s Receiver: %s - + **Limits** Given: %s in %s hours Received: %s in %s hours Per Message: %s Cooldown: %s - + **Age** Max Age: %s minutes Min Messages: %s diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Announcements.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Announcements.java index 58d90e98e..393f115f0 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Announcements.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Announcements.java @@ -18,12 +18,23 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Handles announcements settings for a guild. + */ public class Announcements implements GuildHolder { private final Settings settings; private boolean active = false; private boolean sameChannel = true; private long channelId = 0; + /** + * Constructs an Announcements object with specified settings. + * + * @param settings the settings + * @param active whether the announcements are active + * @param sameChannel whether the announcements should be sent to the same channel + * @param channelId the ID of the channel for announcements + */ private Announcements(Settings settings, boolean active, boolean sameChannel, long channelId) { this.settings = settings; this.active = active; @@ -31,10 +42,23 @@ private Announcements(Settings settings, boolean active, boolean sameChannel, lo this.channelId = channelId; } + /** + * Constructs an Announcements object with specified settings. + * + * @param settings the settings + */ public Announcements(Settings settings) { this.settings = settings; } + /** + * Builds an Announcements object from the database row. + * + * @param settings the settings + * @param rs the database row + * @return the Announcements object + * @throws SQLException if a database access error occurs + */ public static Announcements build(Settings settings, Row rs) throws SQLException { return new Announcements(settings, rs.getBoolean("active"), @@ -42,18 +66,39 @@ public static Announcements build(Settings settings, Row rs) throws SQLException rs.getLong("channel_id")); } + /** + * Checks if the announcements are active. + * + * @return true if active, false otherwise + */ public boolean isActive() { return active; } + /** + * Checks if the announcements should be sent to the same channel. + * + * @return true if same channel, false otherwise + */ public boolean isSameChannel() { return sameChannel; } + /** + * Gets the ID of the channel for announcements. + * + * @return the channel ID + */ public long channelId() { return channelId; } + /** + * Sets the active status of the announcements. + * + * @param active the active status + * @return the updated active status + */ public boolean active(boolean active) { if (set("active", stmt -> stmt.bind(active))) { this.active = active; @@ -61,6 +106,12 @@ public boolean active(boolean active) { return this.active; } + /** + * Sets whether the announcements should be sent to the same channel. + * + * @param sameChannel the same channel status + * @return the updated same channel status + */ public boolean sameChannel(boolean sameChannel) { if (set("same_channel", stmt -> stmt.bind(sameChannel))) { this.sameChannel = sameChannel; @@ -68,6 +119,12 @@ public boolean sameChannel(boolean sameChannel) { return this.sameChannel; } + /** + * Sets the channel for announcements. + * + * @param textChannel the text channel + * @return the updated channel ID + */ public long channel(TextChannel textChannel) { if (set("channel_id", stmt -> stmt.bind(textChannel.getIdLong()))) { channelId = textChannel.getIdLong(); @@ -75,6 +132,13 @@ public long channel(TextChannel textChannel) { return channelId; } + /** + * Sets a parameter in the database. + * + * @param parameter the parameter to set + * @param builder the function to build the call + * @return true if the parameter was set successfully, false otherwise + */ private boolean set(String parameter, Function builder) { return query(""" INSERT INTO announcements(guild_id, %s) VALUES (?, ?) @@ -86,16 +150,31 @@ ON CONFLICT(guild_id) .changed(); } + /** + * Gets the guild associated with the settings. + * + * @return the guild + */ @Override public Guild guild() { return settings.guild(); } + /** + * Gets the ID of the guild associated with the settings. + * + * @return the guild ID + */ @Override public long guildId() { return settings.guildId(); } - + + /** + * Returns a pretty string representation of the announcement settings. + * + * @return the pretty string + */ public String prettyString() { return """ Active: %s diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/General.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/General.java index b09f2bed9..4d64e6b1b 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/General.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/General.java @@ -23,6 +23,9 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Represents the general settings for a guild. + */ public class General implements GuildHolder { private final AtomicBoolean stackRoles; private final Settings settings; @@ -31,10 +34,25 @@ public class General implements GuildHolder { private ReputationMode reputationMode; private LocalDate resetDate; + /** + * Constructs a new General instance with default values. + * + * @param settings the Settings instance + */ public General(Settings settings) { this(settings, null, true, false, ReputationMode.TOTAL, null); } + /** + * Constructs a new General instance with specified values. + * + * @param settings the Settings instance + * @param language the DiscordLocale for the language + * @param emojiDebug whether emoji debug is enabled + * @param stackRoles whether stack roles is enabled + * @param reputationMode the ReputationMode + * @param resetDate the reset date + */ public General(Settings settings, DiscordLocale language, boolean emojiDebug, boolean stackRoles, ReputationMode reputationMode, LocalDate resetDate) { this.settings = settings; this.language = language; @@ -44,6 +62,14 @@ public General(Settings settings, DiscordLocale language, boolean emojiDebug, bo this.resetDate = resetDate; } + /** + * Builds a General instance from the given database row. + * + * @param settings the Settings instance + * @param rs the database row + * @return the General instance + * @throws SQLException if a database access error occurs + */ public static General build(Settings settings, Row rs) throws SQLException { var lang = rs.getString("language"); return new General(settings, @@ -54,6 +80,12 @@ public static General build(Settings settings, Row rs) throws SQLException { Optional.ofNullable(rs.getDate("reset_date")).map(Date::toLocalDate).orElse(null)); } + /** + * Sets the language for the guild. + * + * @param language the DiscordLocale for the language + * @return true if the language was successfully set, false otherwise + */ public boolean language(@Nullable DiscordLocale language) { var result = set("language", stmt -> stmt.bind(language == null ? null : language.getLocale())); if (result) { @@ -62,6 +94,12 @@ public boolean language(@Nullable DiscordLocale language) { return result; } + /** + * Sets the emoji debug status for the guild. + * + * @param emojiDebug whether emoji debug is enabled + * @return true if the emoji debug status was successfully set, false otherwise + */ public boolean emojiDebug(boolean emojiDebug) { var result = set("emoji_debug", stmt -> stmt.bind(emojiDebug)); if (result) { @@ -70,6 +108,12 @@ public boolean emojiDebug(boolean emojiDebug) { return result; } + /** + * Sets the reputation mode for the guild. + * + * @param reputationMode the ReputationMode + * @return the ReputationMode that was set + */ public ReputationMode reputationMode(ReputationMode reputationMode) { var result = set("reputation_mode", stmt -> stmt.bind(reputationMode.name())); if (result) { @@ -78,6 +122,12 @@ public ReputationMode reputationMode(ReputationMode reputationMode) { return reputationMode; } + /** + * Sets the stack roles status for the guild. + * + * @param stackRoles whether stack roles is enabled + * @return true if the stack roles status was successfully set, false otherwise + */ public boolean stackRoles(boolean stackRoles) { var result = set("stack_roles", stmt -> stmt.bind(stackRoles)); if (result) { @@ -86,6 +136,12 @@ public boolean stackRoles(boolean stackRoles) { return result; } + /** + * Sets the reset date for the guild. + * + * @param resetDate the reset date + * @return true if the reset date was successfully set, false otherwise + */ public boolean resetDate(LocalDate resetDate) { var result = set("reset_date", stmt -> stmt.bind(resetDate == null ? null : Date.valueOf(resetDate))); if (result) { @@ -94,36 +150,78 @@ public boolean resetDate(LocalDate resetDate) { return result; } + /** + * Retrieves the language for the guild. + * + * @return an Optional containing the DiscordLocale for the language, or an empty Optional if not set + */ public Optional language() { return Optional.ofNullable(language); } + /** + * Checks if emoji debug is enabled for the guild. + * + * @return true if emoji debug is enabled, false otherwise + */ public boolean isEmojiDebug() { return emojiDebug; } + /** + * Checks if stack roles is enabled for the guild. + * + * @return true if stack roles is enabled, false otherwise + */ public boolean isStackRoles() { return stackRoles.get(); } + /** + * Retrieves the AtomicBoolean representing the stack roles status for the guild. + * + * @return the AtomicBoolean representing the stack roles status + */ public AtomicBoolean stackRoles() { return stackRoles; } + /** + * Retrieves the reset date for the guild. + * + * @return the reset date + */ public LocalDate resetDate() { return resetDate; } + /** + * Retrieves the guild associated with this instance. + * + * @return the guild + */ @Override public Guild guild() { return settings.guild(); } + /** + * Retrieves the ID of the guild associated with this instance. + * + * @return the guild ID + */ @Override public long guildId() { return settings.guildId(); } + /** + * Sets a parameter in the database for the guild. + * + * @param parameter the parameter to set + * @param builder the function to build the Call + * @return true if the parameter was successfully set, false otherwise + */ private boolean set(String parameter, Function builder) { return query(""" INSERT INTO guild_settings(guild_id, %s) VALUES (?, ?) @@ -135,10 +233,20 @@ ON CONFLICT(guild_id) .changed(); } + /** + * Retrieves the reputation mode for the guild. + * + * @return the ReputationMode + */ public ReputationMode reputationMode() { return reputationMode; } + /** + * Returns a pretty string representation of the general settings. + * + * @return a pretty string representation of the general settings + */ public String prettyString() { return """ Stack roles: %s diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Messages.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Messages.java index c7e68702d..24061acc1 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Messages.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Messages.java @@ -19,24 +19,52 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Manages the message settings for a guild. + */ public class Messages implements GuildHolder { private final Settings settings; private boolean reactionConfirmation; + /** + * Constructs a Messages object with the specified settings and default reaction confirmation. + * + * @param settings the settings object + */ public Messages(Settings settings) { this(settings, true); } + /** + * Constructs a Messages object with the specified settings and reaction confirmation. + * + * @param settings the settings object + * @param reactionConfirmation the reaction confirmation setting + */ public Messages(Settings settings, boolean reactionConfirmation) { this.settings = settings; this.reactionConfirmation = reactionConfirmation; } + /** + * Builds a Messages object from the specified settings and database row. + * + * @param settings the settings object + * @param rs the database row + * @return the constructed Messages object + * @throws SQLException if a database access error occurs + */ public static Messages build(Settings settings, Row rs) throws SQLException { return new Messages(settings, rs.getBoolean("reaction_confirmation")); } + /** + * Sets the reaction confirmation setting. + * + * @param reactionConfirmation the new reaction confirmation setting + * @return the updated reaction confirmation setting + */ public boolean reactionConfirmation(boolean reactionConfirmation) { var result = set("reaction_confirmation", stmt -> stmt.bind(reactionConfirmation)); if (result) { @@ -45,20 +73,42 @@ public boolean reactionConfirmation(boolean reactionConfirmation) { return this.reactionConfirmation; } + /** + * Returns the current reaction confirmation setting. + * + * @return true if reaction confirmation is enabled, false otherwise + */ public boolean isReactionConfirmation() { return reactionConfirmation; } + /** + * Returns the guild associated with this Messages object. + * + * @return the guild + */ @Override public Guild guild() { return settings.guild(); } + /** + * Returns the guild ID associated with this Messages object. + * + * @return the guild ID + */ @Override public long guildId() { return settings.guildId(); } + /** + * Sets a parameter in the message states table. + * + * @param parameter the parameter name + * @param builder the function to build the query call + * @return true if the parameter was successfully set, false otherwise + */ private boolean set(String parameter, Function builder) { return query(""" INSERT INTO message_states(guild_id, %s) VALUES (?, ?) @@ -70,6 +120,11 @@ ON CONFLICT(guild_id) .changed(); } + /** + * Returns a localized string representation of the message settings. + * + * @return the localized string representation + */ public String toLocalizedString() { var setting = List.of( getSetting("command.messages.states.message.option.reactionconfirmation.name", isReactionConfirmation()) @@ -78,10 +133,22 @@ public String toLocalizedString() { return String.join("\n", setting); } + /** + * Returns a localized setting string. + * + * @param locale the locale key + * @param object the setting value + * @return the localized setting string + */ private String getSetting(@PropertyKey(resourceBundle = "locale") String locale, boolean object) { return String.format("$%s$: $%s$", locale, object ? "words.enabled" : "words.disabled"); } + /** + * Returns a pretty string representation of the message settings. + * + * @return the pretty string representation + */ public String prettyString() { return """ Reaction confirmation: %s diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Ranks.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Ranks.java index 0ad78d90d..f8ef351ae 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Ranks.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Ranks.java @@ -22,23 +22,32 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Manages the reputation ranks for a guild. + */ public class Ranks implements GuildHolder { private final LinkedHashSet ranks = new LinkedHashSet<>(); private final Settings settings; private final AtomicBoolean stackRoles; + /** + * Constructs a Ranks instance. + * + * @param settings the settings for the guild + * @param stackRoles whether to stack roles + */ public Ranks(Settings settings, AtomicBoolean stackRoles) { this.settings = settings; this.stackRoles = stackRoles; } /** - * Add a reputation rank. + * Adds a reputation rank. *

- * If the role or the reputation amount is already in use it will be removed first. + * If the role or the reputation amount is already in use, it will be removed first. * - * @param role role - * @param reputation required reputation of role + * @param role the role + * @param reputation the required reputation of the role * @return true if the role was added or updated */ public boolean add(Role role, long reputation) { @@ -71,6 +80,11 @@ ON CONFLICT(guild_id, role_id) return deleteRank; } + /** + * Retrieves the list of reputation ranks. + * + * @return the list of reputation ranks + */ public List ranks() { if (!ranks.isEmpty()) { return ranks.stream().sorted().toList(); @@ -98,8 +112,8 @@ public List ranks() { *

* This will contain up to {@link #ranks()}.size() when {@link General#stackRoles()} is false. * - * @param user user to check - * @return list of ranks + * @param user the user to check + * @return the list of ranks */ public List currentRanks(RepUser user) { var profile = user.profile(); @@ -110,6 +124,12 @@ public List currentRanks(RepUser user) { .toList(); } + /** + * Gets the current rank of the user. + * + * @param user the user to check + * @return an optional containing the current rank if found, otherwise empty + */ public Optional currentRank(RepUser user) { var profile = user.profile(); return ranks().stream() @@ -119,22 +139,44 @@ public Optional currentRank(RepUser user) { .findFirst(); } + /** + * Gets the next rank of the user. + * + * @param user the user to check + * @return an optional containing the next rank if found, otherwise empty + */ public Optional nextRank(RepUser user) { var profile = user.profile(); return ranks().stream().filter(rank -> rank.reputation() > profile.reputation()) .sorted(Comparator.reverseOrder()).limit(1).findFirst(); } + /** + * Retrieves the guild associated with this instance. + * + * @return the guild + */ @Override public Guild guild() { return settings.guild(); } + /** + * Retrieves the guild ID associated with this instance. + * + * @return the guild ID + */ @Override public long guildId() { return settings.guildId(); } + /** + * Gets the rank associated with the specified role. + * + * @param role the role + * @return an optional containing the rank if found, otherwise empty + */ public Optional rank(Role role) { return query("SELECT reputation FROM guild_ranks WHERE guild_id = ? AND role_id = ?") .single(call().bind(guildId()).bind(role.getIdLong())) @@ -142,10 +184,18 @@ public Optional rank(Role role) { .first(); } + /** + * Refreshes the ranks by clearing the current list. + */ public void refresh() { ranks.clear(); } + /** + * Generates a pretty string representation of the ranks. + * + * @return a pretty string representation of the ranks + */ public String prettyString() { return ranks().stream().filter(r -> r.role().isPresent()) .map(rank -> "%s(%d) %d".formatted(rank.role().get().getName(), rank.role().get().getPosition(), rank.reputation())) diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Reputation.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Reputation.java index 360ec50b5..d36be1f15 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Reputation.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Reputation.java @@ -19,6 +19,9 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Represents the reputation settings for a guild. + */ public class Reputation implements GuildHolder { private final Settings settings; private boolean reactionActive; @@ -28,10 +31,26 @@ public class Reputation implements GuildHolder { private boolean embedActive; private boolean directActive; + /** + * Constructs a Reputation object with the specified settings and default values. + * + * @param settings the settings object + */ public Reputation(Settings settings) { this(settings, true, true, true, true, true, false); } + /** + * Constructs a Reputation object with the specified settings and values. + * + * @param settings the settings object + * @param reactionActive whether reactions are active + * @param answerActive whether answers are active + * @param mentionActive whether mentions are active + * @param fuzzyActive whether fuzzy matching is active + * @param embedActive whether embeds are active + * @param directActive whether direct messages are active + */ public Reputation(Settings settings, boolean reactionActive, boolean answerActive, boolean mentionActive, boolean fuzzyActive, boolean embedActive, boolean directActive) { this.settings = settings; this.reactionActive = reactionActive; @@ -42,6 +61,14 @@ public Reputation(Settings settings, boolean reactionActive, boolean answerActiv this.directActive = directActive; } + /** + * Builds a Reputation object from the specified settings and row. + * + * @param settings the settings object + * @param rs the row object + * @return the Reputation object + * @throws SQLException if a database access error occurs + */ public static Reputation build(Settings settings, Row rs) throws SQLException { return new Reputation(settings, rs.getBoolean("reactions_active"), @@ -52,30 +79,66 @@ public static Reputation build(Settings settings, Row rs) throws SQLException { rs.getBoolean("skip_single_embed")); } + /** + * Returns whether reactions are active. + * + * @return true if reactions are active, false otherwise + */ public boolean isReactionActive() { return reactionActive; } + /** + * Returns whether answers are active. + * + * @return true if answers are active, false otherwise + */ public boolean isAnswerActive() { return answerActive; } + /** + * Returns whether mentions are active. + * + * @return true if mentions are active, false otherwise + */ public boolean isMentionActive() { return mentionActive; } + /** + * Returns whether fuzzy matching is active. + * + * @return true if fuzzy matching is active, false otherwise + */ public boolean isFuzzyActive() { return fuzzyActive; } + /** + * Returns whether embeds are active. + * + * @return true if embeds are active, false otherwise + */ public boolean isEmbedActive() { return embedActive; } + /** + * Returns whether direct messages are active. + * + * @return true if direct messages are active, false otherwise + */ public boolean isDirectActive() { return directActive; } + /** + * Sets whether embeds are active. + * + * @param embedActive true to activate embeds, false to deactivate + * @return the updated embed active status + */ public boolean embedActive(boolean embedActive) { var result = set("embed_active", stmt -> stmt.bind(embedActive)); if (result) { @@ -84,6 +147,12 @@ public boolean embedActive(boolean embedActive) { return this.embedActive; } + /** + * Sets whether reactions are active. + * + * @param reactionActive true to activate reactions, false to deactivate + * @return the updated reaction active status + */ public boolean reactionActive(boolean reactionActive) { var result = set("reactions_active", stmt -> stmt.bind(reactionActive)); if (result) { @@ -92,6 +161,12 @@ public boolean reactionActive(boolean reactionActive) { return this.reactionActive; } + /** + * Sets whether answers are active. + * + * @param answerActive true to activate answers, false to deactivate + * @return the updated answer active status + */ public boolean answerActive(boolean answerActive) { var result = set("answer_active", stmt -> stmt.bind(answerActive)); if (result) { @@ -100,6 +175,12 @@ public boolean answerActive(boolean answerActive) { return this.answerActive; } + /** + * Sets whether mentions are active. + * + * @param mentionActive true to activate mentions, false to deactivate + * @return the updated mention active status + */ public boolean mentionActive(boolean mentionActive) { var result = set("mention_active", stmt -> stmt.bind(mentionActive)); if (result) { @@ -108,6 +189,12 @@ public boolean mentionActive(boolean mentionActive) { return this.mentionActive; } + /** + * Sets whether fuzzy matching is active. + * + * @param fuzzyActive true to activate fuzzy matching, false to deactivate + * @return the updated fuzzy active status + */ public boolean fuzzyActive(boolean fuzzyActive) { var result = set("fuzzy_active", stmt -> stmt.bind(fuzzyActive)); if (result) { @@ -116,6 +203,12 @@ public boolean fuzzyActive(boolean fuzzyActive) { return this.fuzzyActive; } + /** + * Sets whether direct messages are active. + * + * @param directActive true to activate direct messages, false to deactivate + * @return the updated direct active status + */ public boolean directActive(boolean directActive) { var result = set("skip_single_embed", stmt -> stmt.bind(directActive)); if (result) { @@ -124,6 +217,11 @@ public boolean directActive(boolean directActive) { return this.directActive; } + /** + * Returns a localized string representation of the reputation settings. + * + * @return the localized string representation + */ public String toLocalizedString() { var setting = List.of( getSetting("command.repsettings.info.message.option.byreaction.name", isReactionActive()), @@ -143,24 +241,55 @@ public String toLocalizedString() { return String.join("\n", setting); } + /** + * Returns a localized setting string. + * + * @param locale the locale key + * @param object the object to be localized + * @return the localized setting string + */ private String getSetting(@PropertyKey(resourceBundle = "locale") String locale, boolean object) { return getSetting(locale, object ? "words.enabled" : "words.disabled"); } + /** + * Returns a localized setting string. + * + * @param locale the locale key + * @param object the object to be localized + * @return the localized setting string + */ private String getSetting(@PropertyKey(resourceBundle = "locale") String locale, String object) { return String.format("$%s$: $%s$", locale, object); } + /** + * Returns the guild associated with the settings. + * + * @return the guild + */ @Override public Guild guild() { return settings.guild(); } + /** + * Returns the guild ID associated with the settings. + * + * @return the guild ID + */ @Override public long guildId() { return settings.guildId(); } + /** + * Sets a parameter in the reputation settings. + * + * @param parameter the parameter to set + * @param builder the function to build the call + * @return true if the parameter was set successfully, false otherwise + */ private boolean set(String parameter, Function builder) { return query(""" INSERT INTO reputation_settings(guild_id, %s) VALUES (?, ?) @@ -172,6 +301,11 @@ ON CONFLICT(guild_id) .changed(); } + /** + * Returns a pretty string representation of the reputation settings. + * + * @return the pretty string representation + */ public String prettyString() { return """ Reaction active: %s diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/ReputationMode.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/ReputationMode.java index 95ff808a9..ff95fb27f 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/ReputationMode.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/ReputationMode.java @@ -5,11 +5,43 @@ */ package de.chojo.repbot.dao.access.guild.settings.sub; +/** + * Enum representing different reputation modes. + */ public enum ReputationMode { + /** + * Total reputation mode. + *

+ * This mode uses the "user_reputation" table and does not support auto-refresh. + */ TOTAL("user_reputation", "reputationMode.total", true, false), + + /** + * Rolling week reputation mode. + *

+ * This mode uses the "user_reputation_7_days" table and supports auto-refresh. + */ ROLLING_WEEK("user_reputation_7_days", "reputationMode.rollingWeek", true, true), + + /** + * Rolling month reputation mode. + *

+ * This mode uses the "user_reputation_30_days" table and supports auto-refresh. + */ ROLLING_MONTH("user_reputation_30_days", "reputationMode.rollingMonth", true, true), + + /** + * Weekly reputation mode. + *

+ * This mode uses the "user_reputation_week" table and supports auto-refresh. + */ WEEK("user_reputation_week", "reputationMode.week", true, true), + + /** + * Monthly reputation mode. + *

+ * This mode uses the "user_reputation_month" table and supports auto-refresh. + */ MONTH("user_reputation_month", "reputationMode.month", true, true); private final String tableName; @@ -17,6 +49,14 @@ public enum ReputationMode { private final boolean supportsOffset; private final boolean autoRefresh; + /** + * Constructs a ReputationMode enum with the specified parameters. + * + * @param tableName the name of the table associated with the reputation mode + * @param localeCode the locale code for the reputation mode + * @param supportsOffset whether the reputation mode supports offset + * @param autoRefresh whether the reputation mode supports auto-refresh + */ ReputationMode(String tableName, String localeCode, boolean supportsOffset, boolean autoRefresh) { this.tableName = tableName; this.localeCode = localeCode; @@ -24,18 +64,38 @@ public enum ReputationMode { this.autoRefresh = autoRefresh; } + /** + * Returns the table name associated with the reputation mode. + * + * @return the table name + */ public String tableName() { return tableName; } + /** + * Returns whether the reputation mode supports offset. + * + * @return true if the reputation mode supports offset, false otherwise + */ public boolean isSupportsOffset() { return supportsOffset; } + /** + * Returns whether the reputation mode supports auto-refresh. + * + * @return true if the reputation mode supports auto-refresh, false otherwise + */ public boolean isAutoRefresh() { return autoRefresh; } + /** + * Returns the locale code associated with the reputation mode. + * + * @return the locale code + */ public String localeCode() { return localeCode; } diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Thanking.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Thanking.java index 03d9dd7e2..2f6e73d09 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Thanking.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/Thanking.java @@ -21,7 +21,13 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; -public class Thanking implements GuildHolder { +/** + * Class representing the thanking settings for a guild. + */ +public class Thanking implements GuildHolder { + /** + * Default reaction emoji. + */ private static final String DEFAULT_REACTION = "🏅"; private final String mainReaction; private final Settings settings; @@ -33,16 +39,36 @@ public class Thanking implements GuildHolder { private Reactions reactions; private Thankwords thankwords; + /** + * Constructs a new Thanking instance with default reaction and channel whitelist enabled. + * + * @param settings the settings for the guild + */ public Thanking(Settings settings) { this(settings, DEFAULT_REACTION, true); } + /** + * Constructs a new Thanking instance with specified reaction and channel whitelist setting. + * + * @param settings the settings for the guild + * @param mainReaction the main reaction emoji + * @param channelWhitelist whether the channel whitelist is enabled + */ public Thanking(Settings settings, String mainReaction, boolean channelWhitelist) { this.settings = settings; this.mainReaction = mainReaction; this.channelWhitelist = channelWhitelist; } + /** + * Builds a Thanking instance from the given settings and database row. + * + * @param settings the settings for the guild + * @param row the database row containing the thanking settings + * @return a new Thanking instance + * @throws SQLException if a database access error occurs + */ public static Thanking build(Settings settings, Row row) throws SQLException { return new Thanking(settings, row.getString("reaction"), @@ -50,6 +76,11 @@ public static Thanking build(Settings settings, Row row) throws SQLException { ); } + /** + * Retrieves the channels associated with the thanking settings. + * + * @return the channels associated with the thanking settings + */ public Channels channels() { if (channels != null) { return channels; @@ -74,6 +105,11 @@ public Channels channels() { return this.channels; } + /** + * Retrieves the donor roles associated with the thanking settings. + * + * @return the donor roles associated with the thanking settings + */ public DonorRoles donorRoles() { if (donorRoles != null) { return donorRoles; @@ -91,6 +127,11 @@ public DonorRoles donorRoles() { return donorRoles; } + /** + * Retrieves the receiver roles associated with the thanking settings. + * + * @return the receiver roles associated with the thanking settings + */ public ReceiverRoles receiverRoles() { if (receiverRoles != null) { return receiverRoles; @@ -108,6 +149,11 @@ public ReceiverRoles receiverRoles() { return receiverRoles; } + /** + * Retrieves the reactions associated with the thanking settings. + * + * @return the reactions associated with the thanking settings + */ public Reactions reactions() { if (reactions != null) { return reactions; @@ -124,6 +170,11 @@ public Reactions reactions() { return this.reactions; } + /** + * Retrieves the thankwords associated with the thanking settings. + * + * @return the thankwords associated with the thanking settings + */ public Thankwords thankwords() { if (thankwords != null) { return thankwords; @@ -141,11 +192,21 @@ public Thankwords thankwords() { return this.thankwords; } + /** + * Retrieves the guild associated with the thanking settings. + * + * @return the guild associated with the thanking settings + */ @Override public Guild guild() { return settings.guild(); } + /** + * Retrieves the guild ID associated with the thanking settings. + * + * @return the guild ID associated with the thanking settings + */ @Override public long guildId() { return settings.guildId(); diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Channels.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Channels.java index dc9c778dc..421b84776 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Channels.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Channels.java @@ -27,7 +27,10 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; -public class Channels implements GuildHolder { +/** + * Class representing the channels configuration for thanking settings. + */ +public class Channels implements GuildHolder { private static final Logger log = getLogger(Channels.class); @@ -36,6 +39,14 @@ public class Channels implements GuildHolder { private final Set categories; private boolean whitelist; + /** + * Constructs a Channels instance with the specified thanking settings, whitelist status, channels, and categories. + * + * @param thanking the thanking settings + * @param whitelist the whitelist status + * @param channels the set of channel IDs + * @param categories the set of category IDs + */ public Channels(Thanking thanking, boolean whitelist, Set channels, Set categories) { this.thanking = thanking; this.whitelist = whitelist; @@ -53,6 +64,12 @@ public long guildId() { return thanking.guildId(); } + /** + * Checks if the given channel is enabled for thanking. + * + * @param channel the guild message channel + * @return true if the channel is enabled, false otherwise + */ public boolean isEnabled(GuildMessageChannel channel) { StandardGuildChannel baseChannel; if (channel instanceof ThreadChannel bc) { @@ -71,40 +88,72 @@ public boolean isEnabled(GuildMessageChannel channel) { return isEnabledByChannel(baseChannel) || isEnabledByCategory(baseChannel.getParentCategory()); } + /** + * Checks if the given channel is enabled by channel ID. + * + * @param channel the standard guild channel + * @return true if the channel is enabled, false otherwise + */ public boolean isEnabledByChannel(StandardGuildChannel channel) { return isWhitelist() == channels.contains(channel.getIdLong()); } + /** + * Checks if the given category is enabled by category ID. + * + * @param category the category + * @return true if the category is enabled, false otherwise + */ public boolean isEnabledByCategory(@Nullable Category category) { if (category == null) return false; return isWhitelist() == categories.contains(category.getIdLong()); } + /** + * Gets the list of enabled guild channels. + * + * @return the list of enabled guild channels + */ public List channels() { return channels.stream().map(guild()::getGuildChannelById) .filter(Objects::nonNull) .toList(); } + /** + * Gets the list of enabled categories. + * + * @return the list of enabled categories + */ public List categories() { return categories.stream().map(guild()::getCategoryById) .filter(Objects::nonNull) .toList(); } + /** + * Gets the set of channel IDs. + * + * @return the set of channel IDs + */ public Set channelIds() { return channels; } + /** + * Checks if the whitelist is enabled. + * + * @return true if the whitelist is enabled, false otherwise + */ public boolean isWhitelist() { return whitelist; } /** - * Add a channel to reputation channel + * Adds a channel to the reputation channels. * - * @param channel channel - * @return true if a channel was added + * @param channel the standard guild channel + * @return true if the channel was added, false otherwise */ public boolean add(StandardGuildChannel channel) { var result = query("INSERT INTO active_channel(guild_id, channel_id) VALUES(?,?) ON CONFLICT(guild_id, channel_id) DO NOTHING;") @@ -118,10 +167,10 @@ public boolean add(StandardGuildChannel channel) { } /** - * Add a category to reputation categories + * Adds a category to the reputation categories. * - * @param category category - * @return true if a category was added + * @param category the category + * @return true if the category was added, false otherwise */ public boolean add(Category category) { var result = query("INSERT INTO active_categories(guild_id, category_id) VALUES(?,?) ON CONFLICT(guild_id, category_id) DO NOTHING;") @@ -135,10 +184,10 @@ public boolean add(Category category) { } /** - * Remove a reputation channel + * Removes a reputation channel. * - * @param channel channel - * @return true if the channel was removed + * @param channel the channel + * @return true if the channel was removed, false otherwise */ public boolean remove(Channel channel) { var result = query("DELETE FROM active_channel WHERE guild_id = ? AND channel_id = ?;") @@ -152,13 +201,13 @@ public boolean remove(Channel channel) { } /** - * Remove a reputation category + * Removes a reputation category. * - * @param category category - * @return true if the channel was removed + * @param category the category + * @return true if the category was removed, false otherwise */ public boolean remove(Category category) { - var result =query("DELETE FROM active_categories WHERE guild_id = ? AND category_id = ?;") + var result = query("DELETE FROM active_categories WHERE guild_id = ? AND category_id = ?;") .single(call().bind(guildId()).bind(category.getIdLong())) .update() .changed(); @@ -169,9 +218,9 @@ public boolean remove(Category category) { } /** - * Remove all channel of a guild + * Removes all channels of a guild. * - * @return the amount of removed channel + * @return the number of removed channels */ public int clearChannel() { var result = query("DELETE FROM active_channel WHERE guild_id = ?;") @@ -185,9 +234,9 @@ public int clearChannel() { } /** - * Remove all categories of a guild + * Removes all categories of a guild. * - * @return the amount of removed categories + * @return the number of removed categories */ public int clearCategories() { var result = query("DELETE FROM active_categories WHERE guild_id = ?;") @@ -200,6 +249,12 @@ public int clearCategories() { return result; } + /** + * Sets the list type to whitelist or blacklist. + * + * @param whitelist the whitelist status + * @return true if the whitelist status was updated, false otherwise + */ public boolean listType(boolean whitelist) { var result = query(""" INSERT INTO thank_settings(guild_id, channel_whitelist) VALUES (?,?) diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/DonorRoles.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/DonorRoles.java index b53c95fee..0cbe18f0d 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/DonorRoles.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/DonorRoles.java @@ -10,24 +10,48 @@ import java.util.Set; +/** + * Represents the donor roles in a guild. + */ public class DonorRoles extends RolesHolder { private final Thanking thanking; + /** + * Constructs a new DonorRoles instance. + * + * @param thanking the thanking instance + * @param roleIds the set of role IDs + */ public DonorRoles(Thanking thanking, Set roleIds) { super(thanking, roleIds); this.thanking = thanking; } + /** + * Gets the guild associated with the donor roles. + * + * @return the guild + */ @Override public Guild guild() { return thanking.guild(); } + /** + * Gets the ID of the guild associated with the donor roles. + * + * @return the guild ID + */ @Override public long guildId() { return thanking.guildId(); } + /** + * Gets the target table name for the donor roles. + * + * @return the target table name + */ @Override protected String targetTable() { return "donor_roles"; diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Reactions.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Reactions.java index 7b86f5689..3125fd627 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Reactions.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Reactions.java @@ -22,27 +22,53 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; -public class Reactions implements GuildHolder { +/** + * Manages the reactions for thanking in a guild. + */ +public class Reactions implements GuildHolder { private final Thanking thanking; private final Set reactions; private String mainReaction; + /** + * Constructs a Reactions instance. + * + * @param thanking the thanking settings + * @param mainReaction the main reaction + * @param reactions the set of additional reactions + */ public Reactions(Thanking thanking, String mainReaction, Set reactions) { this.thanking = thanking; this.mainReaction = mainReaction; this.reactions = reactions; } + /** + * Gets the guild associated with the reactions. + * + * @return the guild + */ @Override public Guild guild() { return thanking.guild(); } + /** + * Gets the guild ID associated with the reactions. + * + * @return the guild ID + */ @Override public long guildId() { return thanking.guildId(); } + /** + * Checks if the given reaction is a valid reaction. + * + * @param reaction the message reaction + * @return true if the reaction is valid, false otherwise + */ public boolean isReaction(MessageReaction reaction) { if (reaction.getEmoji() instanceof UnicodeEmoji emoji) { return isReaction(emoji.getAsReactionCode()); @@ -53,6 +79,12 @@ public boolean isReaction(MessageReaction reaction) { return false; } + /** + * Checks if the given reaction string is a valid reaction. + * + * @param reaction the reaction string + * @return true if the reaction is valid, false otherwise + */ private boolean isReaction(String reaction) { if (mainReaction.equals(reaction)) { return true; @@ -60,10 +92,20 @@ private boolean isReaction(String reaction) { return reactions.contains(reaction); } + /** + * Checks if the main reaction is an emote. + * + * @return true if the main reaction is an emote, false otherwise + */ public boolean reactionIsEmote() { return Verifier.isValidId(mainReaction()); } + /** + * Gets the mention string for the main reaction. + * + * @return an optional containing the mention string if available, otherwise empty + */ public Optional reactionMention() { if (!reactionIsEmote()) { return Optional.ofNullable(mainReaction()); @@ -72,10 +114,20 @@ public Optional reactionMention() { .map(CustomEmoji::getAsMention); } + /** + * Gets the main reaction string. + * + * @return the main reaction string + */ public String mainReaction() { return mainReaction; } + /** + * Gets the mentions for the additional reactions. + * + * @return a list of additional reaction mentions + */ public List getAdditionalReactionMentions() { return reactions.stream() .map(reaction -> { @@ -90,6 +142,12 @@ public List getAdditionalReactionMentions() { .collect(Collectors.toList()); } + /** + * Adds a new reaction to the set of reactions. + * + * @param reaction the reaction string + * @return true if the reaction was added successfully, false otherwise + */ public boolean add(String reaction) { var result = query(""" INSERT INTO guild_reactions(guild_id, reaction) VALUES (?,?) @@ -105,6 +163,12 @@ ON CONFLICT(guild_id, reaction) return result; } + /** + * Removes a reaction from the set of reactions. + * + * @param reaction the reaction string + * @return true if the reaction was removed successfully, false otherwise + */ public boolean remove(String reaction) { var result = query(""" DELETE FROM guild_reactions WHERE guild_id = ? AND reaction = ?; @@ -119,6 +183,12 @@ public boolean remove(String reaction) { return result; } + /** + * Sets the main reaction. + * + * @param reaction the reaction string + * @return true if the main reaction was set successfully, false otherwise + */ public boolean mainReaction(String reaction) { var result = query(""" INSERT INTO thank_settings(guild_id, reaction) VALUES (?,?) @@ -135,6 +205,11 @@ ON CONFLICT(guild_id) return result; } + /** + * Gets the set of reactions. + * + * @return the set of reactions + */ public Set reactions() { return reactions; } diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/ReceiverRoles.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/ReceiverRoles.java index d3c9bd367..c59f69996 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/ReceiverRoles.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/ReceiverRoles.java @@ -10,24 +10,48 @@ import java.util.Set; +/** + * Manages the roles for receivers in a guild. + */ public class ReceiverRoles extends RolesHolder { private final Thanking thanking; + /** + * Constructs a ReceiverRoles instance. + * + * @param thanking the thanking settings + * @param roleIds the set of role IDs + */ public ReceiverRoles(Thanking thanking, Set roleIds) { super(thanking, roleIds); this.thanking = thanking; } + /** + * Gets the guild associated with the receiver roles. + * + * @return the guild + */ @Override public Guild guild() { return thanking.guild(); } + /** + * Gets the guild ID associated with the receiver roles. + * + * @return the guild ID + */ @Override public long guildId() { return thanking.guildId(); } + /** + * Gets the target table name for receiver roles. + * + * @return the target table name + */ @Override protected String targetTable() { return "receiver_roles"; diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/RolesHolder.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/RolesHolder.java index 418b721b9..33f82077b 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/RolesHolder.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/RolesHolder.java @@ -22,16 +22,40 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; +/** + * Abstract class representing a holder for roles in a guild. + */ public abstract class RolesHolder implements GuildHolder { + /** + * Logger for logging events. + */ private static final Logger log = getLogger(RolesHolder.class); + /** + * Set of role IDs. + */ protected final Set roleIds; + /** + * Thanking settings. + */ protected final Thanking thanking; + /** + * Constructs a new RolesHolder. + * + * @param thanking the thanking settings + * @param roleIds the set of role IDs + */ public RolesHolder(Thanking thanking, Set roleIds) { this.thanking = thanking; this.roleIds = roleIds; } + /** + * Checks if the member has any of the roles in the roleIds set. + * + * @param member the member to check + * @return true if the member has any of the roles, false otherwise + */ public boolean hasRole(@Nullable Member member) { if (member == null) { log.trace("Member is null. Could not determine group."); @@ -44,17 +68,38 @@ public boolean hasRole(@Nullable Member member) { return false; } + /** + * Retrieves the set of roles corresponding to the role IDs. + * + * @return the set of roles + */ public Set roles() { return roleIds.stream().map(guild()::getRoleById).filter(Objects::nonNull).collect(Collectors.toSet()); } + /** + * Retrieves the guild associated with this RolesHolder. + * + * @return the guild + */ @Override public Guild guild() { return thanking.guild(); } + /** + * Retrieves the target table name for database operations. + * + * @return the target table name + */ protected abstract String targetTable(); + /** + * Adds a role to the roleIds set and the database. + * + * @param role the role to add + * @return true if the role was added, false otherwise + */ public boolean add(Role role) { var result = query("INSERT INTO %s(guild_id, role_id) VALUES (?,?) ON CONFLICT(guild_id, role_id) DO NOTHING", targetTable()) .single(call().bind(guildId()).bind(role.getIdLong())) @@ -66,6 +111,12 @@ public boolean add(Role role) { return result; } + /** + * Removes a role from the roleIds set and the database. + * + * @param role the role to remove + * @return true if the role was removed, false otherwise + */ public boolean remove(Role role) { var result = query("DELETE FROM %s WHERE guild_id = ? AND role_id = ?", targetTable()) .single(call().bind(guildId()).bind(role.getIdLong())) @@ -77,6 +128,11 @@ public boolean remove(Role role) { return result; } + /** + * Returns a pretty string representation of the roles. + * + * @return the string representation of the roles + */ public String prettyString() { return roleIds.stream() .map(id -> Optional.ofNullable(guild().getRoleById(id)) diff --git a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Thankwords.java b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Thankwords.java index 1b6c9f23d..2ee197f33 100644 --- a/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Thankwords.java +++ b/src/main/java/de/chojo/repbot/dao/access/guild/settings/sub/thanking/Thankwords.java @@ -18,18 +18,33 @@ import static de.chojo.sadu.queries.api.call.Call.call; import static de.chojo.sadu.queries.api.query.Query.query; +/** + * Class representing the thank words settings for a guild. + */ public class Thankwords implements GuildHolder { + /** + * Regular expression pattern for a thank word. + */ @Language("RegExp") private static final String THANKWORD = "(?:^|\\b)%s(?:$|\\b)"; + + /** + * Regular expression pattern for matching thank words. + */ @Language("RegExp") private static final String PATTERN = "(?i)(?%s)"; private final Thanking thanking; - private final Set thankwords; private final StampedLock lock; private volatile Pattern cachedPattern; + /** + * Constructs a new Thankwords instance. + * + * @param thanking the thanking settings + * @param thankwords the set of thank words + */ public Thankwords(Thanking thanking, Set thankwords) { this.thanking = thanking; this.thankwords = thankwords; @@ -39,16 +54,31 @@ public Thankwords(Thanking thanking, Set thankwords) { this.cachedPattern = compilePattern(); } + /** + * Retrieves the guild associated with the thank words settings. + * + * @return the guild associated with the thank words settings + */ @Override public Guild guild() { return thanking.guild(); } + /** + * Retrieves the guild ID associated with the thank words settings. + * + * @return the guild ID associated with the thank words settings + */ @Override public long guildId() { return thanking.guildId(); } + /** + * Retrieves the set of thank words. + * + * @return the set of thank words + */ public Set words() { long stamp = lock.readLock(); try { @@ -58,6 +88,11 @@ public Set words() { } } + /** + * Retrieves the compiled pattern for matching thank words. + * + * @return the compiled pattern for matching thank words + */ public Pattern thankwordPattern() { // even if another thread has a write-lock, we either read the old pattern before the other thread compiles the new one, // or we read the new one - both fine for our use @@ -65,7 +100,10 @@ public Pattern thankwordPattern() { } /** - * Must be called in a write-lock if 'this' is accessible from other objects + * Compiles the pattern for matching thank words. + * Must be called in a write-lock if 'this' is accessible from other objects. + * + * @return the compiled pattern for matching thank words */ private Pattern compilePattern() { if (thankwords.isEmpty()) return Pattern.compile(""); @@ -76,6 +114,12 @@ private Pattern compilePattern() { Pattern.CASE_INSENSITIVE + Pattern.MULTILINE + Pattern.DOTALL + Pattern.COMMENTS); } + /** + * Adds a new thank word to the set. + * + * @param pattern the thank word pattern to add + * @return true if the thank word was added, false otherwise + */ public boolean add(String pattern) { long stamp = lock.writeLock(); try { @@ -98,6 +142,12 @@ ON CONFLICT(guild_id, thankword) } } + /** + * Removes a thank word from the set. + * + * @param pattern the thank word pattern to remove + * @return true if the thank word was removed, false otherwise + */ public boolean remove(String pattern) { long stamp = lock.writeLock(); try { @@ -120,6 +170,11 @@ public boolean remove(String pattern) { } } + /** + * Retrieves a pretty string representation of the thank words. + * + * @return a pretty string representation of the thank words + */ public String prettyString() { return words().stream().map("`%s`"::formatted).collect(Collectors.joining(", ")); } diff --git a/src/main/java/de/chojo/repbot/dao/access/metrics/Commands.java b/src/main/java/de/chojo/repbot/dao/access/metrics/Commands.java index a57e8d0ad..5511e3c5a 100644 --- a/src/main/java/de/chojo/repbot/dao/access/metrics/Commands.java +++ b/src/main/java/de/chojo/repbot/dao/access/metrics/Commands.java @@ -14,16 +14,26 @@ import java.time.LocalDate; import java.util.Collections; import java.util.List; -import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import static de.chojo.sadu.queries.api.call.Call.call; +/** + * Data access object for handling command metrics. + */ public class Commands { + /** + * Constructs a new Commands instance. + */ public Commands() { } + /** + * Logs a command execution. + * + * @param command the command to log + */ public void logCommand(String command) { Query.query(""" INSERT INTO metrics_commands(day, command) VALUES (now()::DATE, ?) @@ -34,22 +44,57 @@ ON CONFLICT(day,command) .insert(); } + /** + * Retrieves command statistics for a specific week. + * + * @param week the week number + * @return the command statistics for the specified week + */ public CommandsStatistic week(int week) { return get("metrics_commands_week", "week", week); } + /** + * Retrieves command statistics for a specific month. + * + * @param month the month number + * @return the command statistics for the specified month + */ public CommandsStatistic month(int month) { return get("metrics_commands_month", "month", month); } + /** + * Retrieves command execution counts for a specific week. + * + * @param week the week number + * @param count the number of entries to retrieve + * @return the command execution counts for the specified week + */ public CountsStatistic week(int week, int count) { return get("metrics_commands_executed_week", "week", week, count); } + /** + * Retrieves command execution counts for a specific month. + * + * @param month the month number + * @param count the number of entries to retrieve + * @return the command execution counts for the specified month + */ public CountsStatistic month(int month, int count) { return get("metrics_commands_executed_month", "month", month, count); } + /** + * Retrieves command execution counts from the database. + * + * @param table the table name + * @param timeframe the timeframe (week or month) + * @param offset the offset value + * @param count the number of entries to retrieve + * @return the command execution counts + */ private CountsStatistic get(String table, String timeframe, int offset, int count) { return Query.query(""" SELECT %s, @@ -65,6 +110,14 @@ private CountsStatistic get(String table, String timeframe, int offset, int coun .map(CountsStatistic::new); } + /** + * Retrieves command statistics from the database. + * + * @param table the table name + * @param timeframe the timeframe (week or month) + * @param offset the offset value + * @return the command statistics + */ private CommandsStatistic get(String table, String timeframe, int offset) { return Query .query(""" @@ -80,6 +133,12 @@ private CommandsStatistic get(String table, String timeframe, int offset) { .map(this::mapStatistics); } + /** + * Maps a list of command statistics to a CommandsStatistic object. + * + * @param commandStatistics the list of command statistics + * @return the mapped CommandsStatistic object + */ private CommandsStatistic mapStatistics(List commandStatistics) { return commandStatistics.stream() .collect(Collectors.groupingBy(CommandStatistic::date)) diff --git a/src/main/java/de/chojo/repbot/dao/access/metrics/Messages.java b/src/main/java/de/chojo/repbot/dao/access/metrics/Messages.java index dd729901a..e3e33e16b 100644 --- a/src/main/java/de/chojo/repbot/dao/access/metrics/Messages.java +++ b/src/main/java/de/chojo/repbot/dao/access/metrics/Messages.java @@ -12,11 +12,20 @@ import static de.chojo.sadu.queries.api.call.Call.call; +/** + * Provides methods to retrieve and save message metrics. + */ public class Messages { + /** + * Constructs a Messages object. + */ public Messages() { } + /** + * Increments the message count for the current hour. + */ public void countMessage() { Query.query(""" INSERT INTO metrics_message_analyzed(hour, count) VALUES (date_trunc('hour', now()), 1) @@ -27,34 +36,92 @@ ON CONFLICT(hour) .insert(); } + /** + * Retrieves the message counts for a specific hour. + * + * @param hour the hour number + * @param count the number of records to retrieve + * @return the counts statistic for the specified hour + */ public CountsStatistic hour(int hour, int count) { return get("metrics_message_analyzed", "hour", hour, count); } + /** + * Retrieves the message counts for a specific day. + * + * @param day the day number + * @param count the number of records to retrieve + * @return the counts statistic for the specified day + */ public CountsStatistic day(int day, int count) { return get("metrics_message_analyzed_day", "day", day, count); } + /** + * Retrieves the message counts for a specific week. + * + * @param week the week number + * @param count the number of records to retrieve + * @return the counts statistic for the specified week + */ public CountsStatistic week(int week, int count) { return get("metrics_message_analyzed_week", "week", week, count); } + /** + * Retrieves the message counts for a specific month. + * + * @param month the month number + * @param count the number of records to retrieve + * @return the counts statistic for the specified month + */ public CountsStatistic month(int month, int count) { return get("metrics_message_analyzed_month", "month", month, count); } + /** + * Retrieves the total message counts for a specific day. + * + * @param day the day number + * @param count the number of records to retrieve + * @return the counts statistic for the specified day + */ public CountsStatistic totalDay(int day, int count) { return get("metrics_messages_analyzed_total_day", "day", day, count); } + /** + * Retrieves the total message counts for a specific week. + * + * @param week the week number + * @param count the number of records to retrieve + * @return the counts statistic for the specified week + */ public CountsStatistic totalWeek(int week, int count) { return get("metrics_messages_analyzed_total_week", "week", week, count); } + /** + * Retrieves the total message counts for a specific month. + * + * @param month the month number + * @param count the number of records to retrieve + * @return the counts statistic for the specified month + */ public CountsStatistic totalMonth(int month, int count) { return get("metrics_messages_analyzed_total_month", "month", month, count); } + /** + * Retrieves the counts statistic for a specific timeframe. + * + * @param table the table name + * @param timeframe the timeframe column name + * @param offset the offset value + * @param count the number of records to retrieve + * @return the counts statistic + */ private CountsStatistic get(String table, String timeframe, int offset, int count) { return Query.query(""" SELECT %s, diff --git a/src/main/java/de/chojo/repbot/dao/access/metrics/Reputation.java b/src/main/java/de/chojo/repbot/dao/access/metrics/Reputation.java index 2a3def4ad..52dbaaee4 100644 --- a/src/main/java/de/chojo/repbot/dao/access/metrics/Reputation.java +++ b/src/main/java/de/chojo/repbot/dao/access/metrics/Reputation.java @@ -13,67 +13,168 @@ import de.chojo.repbot.dao.snapshots.statistics.builder.LabeledCountStatisticBuilder; import de.chojo.sadu.queries.api.query.Query; -import java.util.concurrent.CompletableFuture; - import static de.chojo.sadu.queries.api.call.Call.call; +/** + * Provides methods to retrieve and save reputation metrics. + */ public class Reputation { + /** + * Constructs a Reputation object. + */ public Reputation() { super(); } + /** + * Retrieves the total reputation counts for a specific week. + * + * @param week the week number + * @param count the number of records to retrieve + * @return the counts statistic for the specified week + */ public CountsStatistic totalWeek(int week, int count) { return get("metrics_reputation_total_week", "week", week, count); } + /** + * Retrieves the total reputation counts for a specific month. + * + * @param month the month number + * @param count the number of records to retrieve + * @return the counts statistic for the specified month + */ public CountsStatistic totalMonth(int month, int count) { return get("metrics_reputation_total_month", "month", month, count); } + /** + * Retrieves the reputation counts for a specific week. + * + * @param week the week number + * @param count the number of records to retrieve + * @return the counts statistic for the specified week + */ public CountsStatistic week(int week, int count) { return get("metrics_reputation_week", "week", week, count); } + /** + * Retrieves the reputation counts for a specific month. + * + * @param month the month number + * @param count the number of records to retrieve + * @return the counts statistic for the specified month + */ public CountsStatistic month(int month, int count) { return get("metrics_reputation_month", "month", month, count); } + /** + * Retrieves the reputation changes for a specific week. + * + * @param week the week number + * @param count the number of records to retrieve + * @return the labeled count statistic for the specified week + */ public LabeledCountStatistic weekChanges(int week, int count) { return getChanges("metrics_reputation_changed_week", "week", week, count); } + /** + * Retrieves the reputation changes for a specific month. + * + * @param month the month number + * @param count the number of records to retrieve + * @return the labeled count statistic for the specified month + */ public LabeledCountStatistic monthChanges(int month, int count) { return getChanges("metrics_reputation_changed_month", "month", month, count); } + /** + * Retrieves the reputation counts by type for a specific week. + * + * @param week the week number + * @param count the number of records to retrieve + * @return the labeled count statistic for the specified week + */ public LabeledCountStatistic typeWeek(int week, int count) { return getType("metrics_reputation_type_week", "week", week, count); } + /** + * Retrieves the reputation counts by type for a specific month. + * + * @param month the month number + * @param count the number of records to retrieve + * @return the labeled count statistic for the specified month + */ public LabeledCountStatistic typeMonth(int month, int count) { return getType("metrics_reputation_type_month", "month", month, count); } + /** + * Retrieves the total reputation counts by type for a specific week. + * + * @param week the week number + * @param count the number of records to retrieve + * @return the labeled count statistic for the specified week + */ public LabeledCountStatistic typeTotalWeek(int week, int count) { return getType("metrics_reputation_type_total_week", "week", week, count); } + /** + * Retrieves the total reputation counts by type for a specific month. + * + * @param month the month number + * @param count the number of records to retrieve + * @return the labeled count statistic for the specified month + */ public LabeledCountStatistic typeTotalMonth(int month, int count) { return getType("metrics_reputation_type_total_month", "month", month, count); } + /** + * Retrieves the reputation counts by day of the week for a specific week. + * + * @param week the week number + * @return the day of the week statistic for the specified week + */ public DowsStatistic dowWeek(int week) { return get("metrics_reputation_dow_week", "week", week); } + /** + * Retrieves the reputation counts by day of the week for a specific month. + * + * @param month the month number + * @return the day of the week statistic for the specified month + */ public DowsStatistic dowMonth(int month) { return get("metrics_reputation_dow_month", "month", month); } + /** + * Retrieves the reputation counts by day of the week for a specific year. + * + * @param year the year number + * @return the day of the week statistic for the specified year + */ public DowsStatistic dowYear(int year) { return get("metrics_reputation_dow_year", "year", year); } + /** + * Retrieves the counts statistic for a specific timeframe. + * + * @param table the table name + * @param timeframe the timeframe column name + * @param offset the offset value + * @param count the number of records to retrieve + * @return the counts statistic + */ private CountsStatistic get(String table, String timeframe, int offset, int count) { return Query.query(""" SELECT %s, @@ -91,6 +192,15 @@ private CountsStatistic get(String table, String timeframe, int offset, int coun .map(CountsStatistic::new); } + /** + * Retrieves the labeled count statistic by type for a specific timeframe. + * + * @param table the table name + * @param timeframe the timeframe column name + * @param offset the offset value + * @param count the number of records to retrieve + * @return the labeled count statistic + */ private LabeledCountStatistic getType(String table, String timeframe, int offset, int count) { var builder = new LabeledCountStatisticBuilder(); Query.query(""" @@ -108,6 +218,15 @@ private LabeledCountStatistic getType(String table, String timeframe, int offset return builder.build(); } + /** + * Retrieves the labeled count statistic for changes for a specific timeframe. + * + * @param table the table name + * @param timeframe the timeframe column name + * @param offset the offset value + * @param count the number of records to retrieve + * @return the labeled count statistic + */ private LabeledCountStatistic getChanges(String table, String timeframe, int offset, int count) { var builder = new LabeledCountStatisticBuilder(); Query.query(""" @@ -128,6 +247,14 @@ private LabeledCountStatistic getChanges(String table, String timeframe, int off return builder.build(); } + /** + * Retrieves the day of the week statistic for a specific timeframe. + * + * @param table the table name + * @param timeframe the timeframe column name + * @param offset the offset value + * @return the day of the week statistic + */ private DowsStatistic get(String table, String timeframe, int offset) { return Query.query(""" SELECT %s, @@ -144,7 +271,7 @@ private DowsStatistic get(String table, String timeframe, int offset) { } /** - * Save reputation counts of the previous day into metric tables. + * Saves the reputation counts of the previous day into metric tables. */ public void saveRepCounts() { Query.query(""" @@ -165,10 +292,10 @@ ON CONFLICT(day, cause) Query.query(""" INSERT INTO metrics_reputation_count(day, count) SELECT now() - INTERVAL '1 DAY', - count(1) + count(1) FROM reputation_log WHERE received < now()::DATE - ON CONFLICT(day) + ON CONFLICT(day) DO UPDATE SET count = excluded.count; """) diff --git a/src/main/java/de/chojo/repbot/dao/access/metrics/Service.java b/src/main/java/de/chojo/repbot/dao/access/metrics/Service.java index 0beb1ce64..84adf771e 100644 --- a/src/main/java/de/chojo/repbot/dao/access/metrics/Service.java +++ b/src/main/java/de/chojo/repbot/dao/access/metrics/Service.java @@ -10,27 +10,45 @@ import de.chojo.repbot.dao.snapshots.statistics.builder.LabeledCountStatisticBuilder; import de.chojo.sadu.queries.api.query.Query; -import java.util.concurrent.CompletableFuture; - import static de.chojo.sadu.queries.api.call.Call.call; +/** + * Service class for handling metrics related to interactions. + */ public class Service { + /** + * Constructs a new Service. + */ public Service() { super(); } + /** + * Logs a successful interaction. + */ public void successfulInteraction() { logInteraction("success"); } + /** + * Logs a failed interaction. + */ public void failedInteraction() { logInteraction("failed"); } + /** + * Logs a counted interaction. + */ public void countInteraction() { logInteraction("count"); } + /** + * Logs an interaction of the specified type. + * + * @param type the type of interaction to log + */ private void logInteraction(String type) { Query.query(""" INSERT INTO metrics_handled_interactions(hour, %s) VALUES (date_trunc('hour', now()), 1) @@ -41,22 +59,59 @@ ON CONFLICT(hour) .insert(); } + /** + * Retrieves the labeled count statistic for the specified hour. + * + * @param hour the hour to retrieve the statistic for + * @param count the number of records to retrieve + * @return the labeled count statistic + */ public LabeledCountStatistic hour(int hour, int count) { return get("metrics_handled_interactions", "hour", hour, count); } + /** + * Retrieves the labeled count statistic for the specified day. + * + * @param day the day to retrieve the statistic for + * @param count the number of records to retrieve + * @return the labeled count statistic + */ public LabeledCountStatistic day(int day, int count) { return get("metrics_handled_interactions_day", "day", day, count); } + /** + * Retrieves the labeled count statistic for the specified week. + * + * @param week the week to retrieve the statistic for + * @param count the number of records to retrieve + * @return the labeled count statistic + */ public LabeledCountStatistic week(int week, int count) { return get("metrics_handled_interactions_week", "week", week, count); } + /** + * Retrieves the labeled count statistic for the specified month. + * + * @param month the month to retrieve the statistic for + * @param count the number of records to retrieve + * @return the labeled count statistic + */ public LabeledCountStatistic month(int month, int count) { return get("metrics_handled_interactions_month", "month", month, count); } + /** + * Retrieves the labeled count statistic for the specified timeframe. + * + * @param table the table to query + * @param timeframe the timeframe to retrieve the statistic for + * @param offset the offset to apply to the timeframe + * @param count the number of records to retrieve + * @return the labeled count statistic + */ private LabeledCountStatistic get(String table, String timeframe, int offset, int count) { var builder = new LabeledCountStatisticBuilder(); return Query.query(""" diff --git a/src/main/java/de/chojo/repbot/dao/access/metrics/Statistic.java b/src/main/java/de/chojo/repbot/dao/access/metrics/Statistic.java index 93d338c0a..309b8cafd 100644 --- a/src/main/java/de/chojo/repbot/dao/access/metrics/Statistic.java +++ b/src/main/java/de/chojo/repbot/dao/access/metrics/Statistic.java @@ -10,24 +10,35 @@ import java.util.Optional; +/** + * Class for accessing and managing statistics in the database. + */ public class Statistic { + /** + * Constructs a new Statistic object. + */ public Statistic() { super(); } + /** + * Retrieves the data statistics from the database. + * + * @return an Optional containing the DataStatistic if present, otherwise an empty Optional + */ public Optional getStatistic() { return Query.query(""" SELECT - guilds, - active_guilds, - active_channel, - channel, - total_reputation, - today_reputation, - weekly_reputation, - weekly_avg_reputation + guilds, + active_guilds, + active_channel, + channel, + total_reputation, + today_reputation, + weekly_reputation, + weekly_avg_reputation FROM - data_statistics; + data_statistics; """) .single() .map(rs -> new DataStatistic( @@ -42,6 +53,9 @@ public Optional getStatistic() { .first(); } + /** + * Refreshes the materialized view of data statistics in the database. + */ public void refreshStatistics() { Query.query("REFRESH MATERIALIZED VIEW data_statistics") .single() diff --git a/src/main/java/de/chojo/repbot/dao/access/metrics/Users.java b/src/main/java/de/chojo/repbot/dao/access/metrics/Users.java index fb24a94d2..11e60806d 100644 --- a/src/main/java/de/chojo/repbot/dao/access/metrics/Users.java +++ b/src/main/java/de/chojo/repbot/dao/access/metrics/Users.java @@ -13,19 +13,48 @@ import static de.chojo.sadu.queries.api.call.Call.call; +/** + * Class for accessing user metrics data. + */ public class Users { + /** + * Constructs a new Users instance. + */ public Users() { super(); } + /** + * Retrieves user statistics for the specified week. + * + * @param offset the offset for the week + * @param count the number of weeks to retrieve + * @return the user statistics for the specified week + */ public UsersStatistic week(int offset, int count) { return get("metrics_users_week", "week", offset, count); } + /** + * Retrieves user statistics for the specified month. + * + * @param offset the offset for the month + * @param count the number of months to retrieve + * @return the user statistics for the specified month + */ public UsersStatistic month(int offset, int count) { return get("metrics_users_month", "month", offset, count); } + /** + * Retrieves user statistics for the specified timeframe. + * + * @param table the table to query + * @param timeframe the timeframe to query (week or month) + * @param offset the offset for the timeframe + * @param count the number of timeframes to retrieve + * @return the user statistics for the specified timeframe + */ private UsersStatistic get(String table, String timeframe, int offset, int count) { return Query.query(""" SELECT %s, @@ -44,7 +73,7 @@ private UsersStatistic get(String table, String timeframe, int offset, int count } /** - * Save the user count of the last week. + * Saves the user count of the last week. */ public void saveUserCountWeek() { Query.query(""" @@ -52,7 +81,7 @@ public void saveUserCountWeek() { SELECT week, receiver_count, donor_count, total_count FROM metrics_unique_users_week WHERE week = date_trunc('week', now() - INTERVAL '1 WEEK') - ON CONFLICT(week) + ON CONFLICT(week) DO UPDATE SET receiver_count = excluded.receiver_count, donor_count = excluded.donor_count, total_count = excluded.donor_count @@ -62,7 +91,7 @@ ON CONFLICT(week) } /** - * Save the user count of the last month. + * Saves the user count of the last month. */ public void saveUserCountMonth() { Query.query(""" @@ -70,7 +99,7 @@ public void saveUserCountMonth() { SELECT month, receiver_count, donor_count, total_count FROM metrics_unique_users_month WHERE month = date_trunc('month', now() - INTERVAL '1 MONTH') - ON CONFLICT(month) + ON CONFLICT(month) DO UPDATE SET receiver_count = excluded.receiver_count, donor_count = excluded.donor_count, total_count = excluded.donor_count diff --git a/src/main/java/de/chojo/repbot/dao/components/GuildHolder.java b/src/main/java/de/chojo/repbot/dao/components/GuildHolder.java index d065e4a18..9582df3c1 100644 --- a/src/main/java/de/chojo/repbot/dao/components/GuildHolder.java +++ b/src/main/java/de/chojo/repbot/dao/components/GuildHolder.java @@ -7,8 +7,22 @@ import net.dv8tion.jda.api.entities.Guild; +/** + * Interface representing a holder for a Guild. + */ public interface GuildHolder { + + /** + * Gets the Guild associated with this holder. + * + * @return the Guild + */ Guild guild(); + /** + * Gets the ID of the Guild associated with this holder. + * + * @return the Guild ID + */ long guildId(); } diff --git a/src/main/java/de/chojo/repbot/dao/components/MemberHolder.java b/src/main/java/de/chojo/repbot/dao/components/MemberHolder.java index cc73f47ce..10ac61486 100644 --- a/src/main/java/de/chojo/repbot/dao/components/MemberHolder.java +++ b/src/main/java/de/chojo/repbot/dao/components/MemberHolder.java @@ -9,23 +9,51 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.User; +/** + * Interface representing a holder for a member, providing access to the member, user, and guild information. + */ public interface MemberHolder extends UserHolder, GuildHolder { + /** + * Retrieves the member associated with this holder. + * + * @return the member + */ Member member(); + /** + * Retrieves the ID of the member associated with this holder. + * + * @return the member ID + */ default long memberId() { return member().getIdLong(); } + /** + * Retrieves the user associated with this holder. + * + * @return the user + */ @Override default User user() { return member().getUser(); } + /** + * Retrieves the guild associated with this holder. + * + * @return the guild + */ @Override default Guild guild() { return member().getGuild(); } + /** + * Retrieves the ID of the guild associated with this holder. + * + * @return the guild ID + */ @Override default long guildId(){ return guild().getIdLong(); diff --git a/src/main/java/de/chojo/repbot/dao/components/UserHolder.java b/src/main/java/de/chojo/repbot/dao/components/UserHolder.java index 0ebdde8c7..2a5b92a8b 100644 --- a/src/main/java/de/chojo/repbot/dao/components/UserHolder.java +++ b/src/main/java/de/chojo/repbot/dao/components/UserHolder.java @@ -7,9 +7,22 @@ import net.dv8tion.jda.api.entities.User; +/** + * Interface representing a holder for a user, providing access to the user information. + */ public interface UserHolder { + /** + * Retrieves the user associated with this holder. + * + * @return the user + */ User user(); + /** + * Retrieves the ID of the user associated with this holder. + * + * @return the user ID + */ default long userId() { return user().getIdLong(); } diff --git a/src/main/java/de/chojo/repbot/dao/pagination/GuildList.java b/src/main/java/de/chojo/repbot/dao/pagination/GuildList.java index 3bd08c7e0..1fc403237 100644 --- a/src/main/java/de/chojo/repbot/dao/pagination/GuildList.java +++ b/src/main/java/de/chojo/repbot/dao/pagination/GuildList.java @@ -11,7 +11,17 @@ import java.util.function.Function; import java.util.function.Supplier; +/** + * Class representing a paginated list of guilds. + */ public class GuildList extends PageAccess { + + /** + * Constructs a new GuildList instance. + * + * @param pagecount a supplier providing the total number of pages + * @param pageSupplier a function providing a list of RepGuild objects for a given page number + */ public GuildList(Supplier pagecount, Function> pageSupplier) { super(pagecount, pageSupplier); } diff --git a/src/main/java/de/chojo/repbot/dao/pagination/GuildRanking.java b/src/main/java/de/chojo/repbot/dao/pagination/GuildRanking.java index 14e2fd239..cd127bcc9 100644 --- a/src/main/java/de/chojo/repbot/dao/pagination/GuildRanking.java +++ b/src/main/java/de/chojo/repbot/dao/pagination/GuildRanking.java @@ -11,14 +11,29 @@ import java.util.function.Function; import java.util.function.Supplier; +/** + * Class representing a paginated list of guild rankings. + */ public class GuildRanking extends PageAccess { private final String title; + /** + * Constructs a new GuildRanking instance. + * + * @param title the title of the guild ranking + * @param pagecount a supplier providing the total number of pages + * @param pageSupplier a function providing a list of RepProfile objects for a given page number + */ public GuildRanking(String title, Supplier pagecount, Function> pageSupplier) { super(pagecount, pageSupplier); this.title = title; } + /** + * Retrieves the title of the guild ranking. + * + * @return the title of the guild ranking + */ public String title() { return title; } diff --git a/src/main/java/de/chojo/repbot/dao/pagination/PageAccess.java b/src/main/java/de/chojo/repbot/dao/pagination/PageAccess.java index a8840c6ee..602374dcc 100644 --- a/src/main/java/de/chojo/repbot/dao/pagination/PageAccess.java +++ b/src/main/java/de/chojo/repbot/dao/pagination/PageAccess.java @@ -12,34 +12,50 @@ import java.util.function.Function; import java.util.function.Supplier; +/** + * Provides access to paginated data. + * + * @param the type of elements in the pages + */ public class PageAccess implements Iterable> { private final Supplier pagecount; private final Function> pageSupplier; + /** + * Constructs a PageAccess object with the specified page count supplier and page supplier. + * + * @param pagecount the supplier for the total number of pages + * @param pageSupplier the function to supply a page of data given a page number + */ public PageAccess(Supplier pagecount, Function> pageSupplier) { this.pagecount = pagecount; this.pageSupplier = pageSupplier; } /** - * The amount of pages which can be accessed. + * Returns the total number of pages. * - * @return page amount + * @return the total number of pages */ public int pages() { return pagecount.get(); } /** - * Get the page. + * Returns the data for the specified page. * - * @param page page on zero based index - * @return a list containing all entries for the page + * @param page the zero-based index of the page + * @return a list containing all entries for the specified page */ public List page(int page) { return pageSupplier.apply(page); } + /** + * Returns an iterator over the pages of data. + * + * @return an iterator over the pages of data + */ @NotNull @Override public Iterator> iterator() { @@ -47,11 +63,21 @@ public Iterator> iterator() { private int currPage = 0; private final int pages = pages(); + /** + * Returns true if there are more pages to iterate over. + * + * @return true if there are more pages to iterate over, false otherwise + */ @Override public boolean hasNext() { return currPage < pages; } + /** + * Returns the next page of data. + * + * @return the next page of data + */ @Override public List next() { return page(currPage++); diff --git a/src/main/java/de/chojo/repbot/dao/pagination/ReputationLogAccess.java b/src/main/java/de/chojo/repbot/dao/pagination/ReputationLogAccess.java index c82c413ad..3e0b0f122 100644 --- a/src/main/java/de/chojo/repbot/dao/pagination/ReputationLogAccess.java +++ b/src/main/java/de/chojo/repbot/dao/pagination/ReputationLogAccess.java @@ -11,7 +11,17 @@ import java.util.function.Function; import java.util.function.Supplier; +/** + * Class for accessing paginated reputation log entries. + */ public class ReputationLogAccess extends PageAccess { + + /** + * Constructs a new ReputationLogAccess. + * + * @param pagecount the supplier for the total number of pages + * @param pageSupplier the function to supply a list of ReputationLogEntry for a given page number + */ public ReputationLogAccess(Supplier pagecount, Function> pageSupplier) { super(pagecount, pageSupplier); } diff --git a/src/main/java/de/chojo/repbot/dao/provider/Guilds.java b/src/main/java/de/chojo/repbot/dao/provider/Guilds.java index 00e6a9826..509dfb23d 100644 --- a/src/main/java/de/chojo/repbot/dao/provider/Guilds.java +++ b/src/main/java/de/chojo/repbot/dao/provider/Guilds.java @@ -23,16 +23,30 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; +/** + * Provides access to guild-related data and operations. + */ public class Guilds { private static final Logger log = getLogger(Guilds.class); private final Cache guilds = CacheBuilder.newBuilder().expireAfterAccess(30, TimeUnit.MINUTES) .build(); private final Configuration configuration; + /** + * Constructs a new Guilds instance. + * + * @param configuration the configuration instance + */ public Guilds(Configuration configuration) { this.configuration = configuration; } + /** + * Retrieves a RepGuild instance for the specified guild. + * + * @param guild the Guild instance + * @return the RepGuild instance + */ public RepGuild guild(Guild guild) { try { return guilds.get(guild.getIdLong(), () -> new RepGuild(guild, configuration)).refresh(guild); @@ -46,7 +60,7 @@ public RepGuild guild(Guild guild) { * Gets a guild by id. This guild object might have limited functionality. This object is never cached. * It should never be used to change settings. *

- * There is no gurantee that this guild will have any data stored in the database. + * There is no guarantee that this guild will have any data stored in the database. * * @param id id of guild to create. * @return repguild created based on an id @@ -56,6 +70,12 @@ public RepGuild byId(long id) { return cached != null ? cached : new RepGuildId(id, configuration); } + /** + * Retrieves a list of guilds by reputation mode. + * + * @param mode the reputation mode + * @return a list of RepGuild instances + */ public List byReputationMode(ReputationMode mode) { return query("SELECT guild_id FROM guild_settings WHERE reputation_mode = ?") .single(call().bind(mode.name())) @@ -63,10 +83,22 @@ public List byReputationMode(ReputationMode mode) { .all(); } + /** + * Retrieves a paginated list of guilds. + * + * @param pageSize the number of guilds per page + * @return a GuildList instance + */ public GuildList guilds(int pageSize) { return new GuildList(() -> pages(pageSize), page -> page(pageSize, page)); } + /** + * Calculates the total number of pages for the given page size. + * + * @param pageSize the number of guilds per page + * @return the total number of pages + */ private Integer pages(int pageSize) { return query(""" SELECT @@ -80,6 +112,13 @@ private Integer pages(int pageSize) { .orElse(1); } + /** + * Retrieves a list of guilds for the specified page. + * + * @param pageSize the number of guilds per page + * @param page the page number + * @return a list of RepGuild instances + */ private List page(int pageSize, int page) { return query(""" SELECT guild_id FROM guilds @@ -91,6 +130,11 @@ private List page(int pageSize, int page) { .all(); } + /** + * Invalidates the cache for the specified guild. + * + * @param guild the guild ID + */ public void invalidate(long guild) { guilds.invalidate(guild); } diff --git a/src/main/java/de/chojo/repbot/dao/provider/Metrics.java b/src/main/java/de/chojo/repbot/dao/provider/Metrics.java index a5406f4cd..e3f0f3d16 100644 --- a/src/main/java/de/chojo/repbot/dao/provider/Metrics.java +++ b/src/main/java/de/chojo/repbot/dao/provider/Metrics.java @@ -14,6 +14,9 @@ import javax.sql.DataSource; +/** + * Provides access to various metrics. + */ public class Metrics { private final Commands commands; private final Messages messages; @@ -22,6 +25,11 @@ public class Metrics { private final Reputation reputation; private final Service service; + /** + * Constructs a new Metrics provider with the specified data source. + * + * @param dataSource the data source to use + */ public Metrics(DataSource dataSource) { commands = new Commands(); messages = new Messages(); @@ -31,26 +39,56 @@ public Metrics(DataSource dataSource) { service = new Service(); } + /** + * Returns the Commands metrics. + * + * @return the Commands metrics + */ public Commands commands() { return commands; } + /** + * Returns the Messages metrics. + * + * @return the Messages metrics + */ public Messages messages() { return messages; } + /** + * Returns the Users metrics. + * + * @return the Users metrics + */ public Users users() { return users; } + /** + * Returns the Statistic metrics. + * + * @return the Statistic metrics + */ public Statistic statistic() { return statistic; } + /** + * Returns the Reputation metrics. + * + * @return the Reputation metrics + */ public Reputation reputation() { return reputation; } + /** + * Returns the Service metrics. + * + * @return the Service metrics + */ public Service service() { return service; } diff --git a/src/main/java/de/chojo/repbot/dao/provider/Voice.java b/src/main/java/de/chojo/repbot/dao/provider/Voice.java index 17079ff44..4e8ccd15a 100644 --- a/src/main/java/de/chojo/repbot/dao/provider/Voice.java +++ b/src/main/java/de/chojo/repbot/dao/provider/Voice.java @@ -17,19 +17,33 @@ import static de.chojo.sadu.queries.api.query.Query.query; import static org.slf4j.LoggerFactory.getLogger; +/** + * Class for handling voice-related data operations. + */ public class Voice { + /** + * Logger for logging events. + */ private static final Logger log = getLogger(Voice.class); + /** + * Configuration settings. + */ private final Configuration configuration; + /** + * Constructs a new Voice instance. + * + * @param configuration the configuration settings + */ public Voice(Configuration configuration) { this.configuration = configuration; } /** - * Log that a user was in a channel with another user. + * Logs that a user was in a channel with other users. * - * @param source the user which has seen the users. - * @param seen the members which were seen by the user lately + * @param source the user who saw the other users + * @param seen the members who were seen by the user */ public void logUser(Member source, List seen) { query(""" @@ -47,13 +61,13 @@ ON CONFLICT(relation_key, guild_id) } /** - * Retrieve the last users which were in a voice channel with the requested user in the last minutes. + * Retrieves the last users who were in a voice channel with the requested user in the last minutes. * - * @param user user to retrieve other users for - * @param guild guild to check + * @param user the user to retrieve other users for + * @param guild the guild to check * @param minutes the amount of past minutes - * @param limit max number of returned ids - * @return list of ids + * @param limit the maximum number of returned IDs + * @return a list of user IDs */ public List getPastUser(User user, Guild guild, int minutes, int limit) { return query(""" @@ -81,7 +95,7 @@ AND seen > now() - (? || 'minute')::INTERVAL } /** - * Cleanup the voice activity + * Cleans up the voice activity data. */ public void cleanup() { query(""" diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/AnalyzerTrace.java b/src/main/java/de/chojo/repbot/dao/snapshots/AnalyzerTrace.java index 36768b197..25fbb9aaa 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/AnalyzerTrace.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/AnalyzerTrace.java @@ -15,7 +15,21 @@ import java.util.ArrayList; import java.util.List; +/** + * Represents a trace of the analyzer, containing the result entry and a list of submit result entries. + * + * @param resultEntry the result entry of the analyzer + * @param submitResultEntries the list of submit result entries + */ public record AnalyzerTrace(ResultEntry resultEntry, List submitResultEntries) { + + /** + * Builds a list of message embeds representing the analyzer trace. + * + * @param guild the guild where the trace is being built + * @param context the event context + * @return a list of message embeds + */ public List embed(Guild guild, EventContext context) { List embeds = new ArrayList<>(); if (resultEntry != null) { diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/GuildReputationStats.java b/src/main/java/de/chojo/repbot/dao/snapshots/GuildReputationStats.java index 74e09f1b1..8d67b6bee 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/GuildReputationStats.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/GuildReputationStats.java @@ -5,5 +5,13 @@ */ package de.chojo.repbot.dao.snapshots; +/** + * Record representing the reputation statistics of a guild. + * + * @param totalReputation the total reputation of the guild + * @param weekReputation the reputation gained by the guild in the past week + * @param todayReputation the reputation gained by the guild today + * @param topChannelId the ID of the top channel in the guild + */ public record GuildReputationStats(int totalReputation, int weekReputation, int todayReputation, long topChannelId) { } diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/RepProfile.java b/src/main/java/de/chojo/repbot/dao/snapshots/RepProfile.java index 4069edcd5..afec89275 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/RepProfile.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/RepProfile.java @@ -27,16 +27,39 @@ /** * Snapshot of a user reputation profile. + * + * @param repUser the reputation user + * @param rank the rank of the user + * @param rankDonated the rank based on donations + * @param userId the ID of the user + * @param reputation the reputation points of the user + * @param repOffset the reputation offset + * @param rawReputation the raw reputation points + * @param donated the amount donated */ public record RepProfile(RepUser repUser, long rank, long rankDonated, long userId, long reputation, long repOffset, - long rawReputation, - long donated) { + long rawReputation, long donated) { private static final int BAR_SIZE = 20; + /** + * Creates an empty RepProfile for the specified user. + * + * @param repuser the reputation user + * @param user the user + * @return an empty RepProfile + */ public static RepProfile empty(RepUser repuser, User user) { return new RepProfile(repuser, 0, user.getIdLong(), 0, 0, 0, 0, 0); } + /** + * Builds a RepProfile from the given database row. + * + * @param repuser the reputation user + * @param rs the database row + * @return a RepProfile + * @throws SQLException if a database access error occurs + */ public static RepProfile buildProfile(RepUser repuser, Row rs) throws SQLException { return new RepProfile(repuser, rs.getLong("rank"), @@ -49,6 +72,13 @@ public static RepProfile buildProfile(RepUser repuser, Row rs) throws SQLExcepti ); } + /** + * Builds a RepProfile for received ranking from the given database row. + * + * @param rs the database row + * @return a RepProfile + * @throws SQLException if a database access error occurs + */ public static RepProfile buildReceivedRanking(Row rs) throws SQLException { return new RepProfile(null, rs.getLong("rank"), @@ -61,16 +91,36 @@ public static RepProfile buildReceivedRanking(Row rs) throws SQLException { ); } + /** + * Generates a fancy string representation of the profile. + * + * @param maxRank the maximum rank + * @return a fancy string representation + */ public String fancyString(int maxRank) { var length = String.valueOf(maxRank).length(); var rank = StringUtils.rightPad(String.valueOf(this.rank), length); return "`" + rank + "` **|** " + MentionUtil.user(userId) + " ➜ " + reputation; } + /** + * Generates a public profile message embed. + * + * @param configuration the configuration + * @param localizer the localization context + * @return a public profile message embed + */ public MessageEmbed publicProfile(Configuration configuration, LocalizationContext localizer) { return getBaseBuilder(configuration, localizer).build(); } + /** + * Generates an admin profile message embed. + * + * @param configuration the configuration + * @param localizer the localization context + * @return an admin profile message embed + */ public MessageEmbed adminProfile(Configuration configuration, LocalizationContext localizer) { var build = getBaseBuilder(configuration, localizer); build.addField("words.rawReputation", String.valueOf(rawReputation()), true) @@ -79,6 +129,13 @@ public MessageEmbed adminProfile(Configuration configuration, LocalizationContex return build.build(); } + /** + * Creates a base embed builder for the profile. + * + * @param configuration the configuration + * @param localizer the localization context + * @return an embed builder + */ private EmbedBuilder getBaseBuilder(Configuration configuration, LocalizationContext localizer) { var ranks = repUser.reputation().repGuild().settings().ranks(); var current = ranks.currentRank(repUser); @@ -108,6 +165,12 @@ private EmbedBuilder getBaseBuilder(Configuration configuration, LocalizationCon return build; } + /** + * Resolves the member associated with this profile in the given guild. + * + * @param guild the guild + * @return an optional containing the member if found, otherwise empty + */ public Optional resolveMember(Guild guild) { try { return Optional.ofNullable(guild.retrieveMemberById(userId()).complete()); diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/ReputationLogEntry.java b/src/main/java/de/chojo/repbot/dao/snapshots/ReputationLogEntry.java index bac7e8dbd..0a74d1cdf 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/ReputationLogEntry.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/ReputationLogEntry.java @@ -19,7 +19,13 @@ * A log entry representing a single reputation. */ public class ReputationLogEntry { + /** + * URL format for Discord message jump links. + */ private static final String PATH = "https://discord.com/channels/%s/%s/%s"; + /** + * Discord epoch timestamp. + */ private static final long DISCORD_EPOCH = 1420070400000L; private final long guildId; private final long channelId; @@ -30,6 +36,19 @@ public class ReputationLogEntry { private final ThankType type; private final LocalDateTime received; + /** + * Constructs a new ReputationLogEntry. + * + * @param log the log instance + * @param guildId the ID of the guild + * @param channelId the ID of the channel + * @param donorId the ID of the donor + * @param receiverId the ID of the receiver + * @param messageId the ID of the message + * @param refMessageId the ID of the reference message + * @param type the type of thank + * @param received the timestamp when the reputation was received + */ public ReputationLogEntry(Log log, long guildId, long channelId, long donorId, long receiverId, long messageId, long refMessageId, ThankType type, LocalDateTime received) { this.guildId = guildId; this.channelId = channelId; @@ -41,6 +60,14 @@ public ReputationLogEntry(Log log, long guildId, long channelId, long donorId, l this.received = received; } + /** + * Builds a ReputationLogEntry from a database row. + * + * @param log the log instance + * @param rs the database row + * @return the created ReputationLogEntry + * @throws SQLException if a database access error occurs + */ public static ReputationLogEntry build(Log log, Row rs) throws SQLException { return new ReputationLogEntry(log, rs.getLong("guild_id"), @@ -53,57 +80,117 @@ public static ReputationLogEntry build(Log log, Row rs) throws SQLException { rs.getTimestamp("received").toLocalDateTime()); } + /** + * Retrieves the jump link for the message. + * + * @return the message jump link + */ public String getMessageJumpLink() { return String.format(PATH, guildId(), channelId(), messageId()); } + /** + * Retrieves the jump link for the reference message. + * + * @return the reference message jump link + */ public String getRefMessageJumpLink() { return String.format(PATH, guildId(), channelId(), refMessageId()); } + /** + * Checks if there is a reference message. + * + * @return true if there is a reference message, false otherwise + */ public boolean hasRefMessage() { return refMessageId != 0; } + /** + * Retrieves the guild ID. + * + * @return the guild ID + */ public long guildId() { return guildId; } + /** + * Retrieves the channel ID. + * + * @return the channel ID + */ public long channelId() { return channelId; } + /** + * Retrieves the donor ID. + * + * @return the donor ID + */ public long donorId() { return donorId; } + /** + * Retrieves the receiver ID. + * + * @return the receiver ID + */ public long receiverId() { return receiverId; } + /** + * Retrieves the message ID. + * + * @return the message ID + */ public long messageId() { return messageId; } + /** + * Retrieves the reference message ID. + * + * @return the reference message ID + */ public long refMessageId() { return refMessageId; } + /** + * Retrieves the type of thank. + * + * @return the type of thank + */ public ThankType type() { return type; } + /** + * Retrieves the timestamp when the reputation was received. + * + * @return the timestamp when the reputation was received + */ public LocalDateTime received() { return received; } + /** + * Retrieves the timestamp in Discord format. + * + * @return the timestamp in Discord format + */ public String timestamp() { var timestamp = ((messageId() >> 22) + DISCORD_EPOCH) / 1000; return String.format(" ", timestamp, timestamp); } /** - * Removes the log entry + * Removes the log entry. */ public void delete() { query("DELETE FROM reputation_log WHERE message_id = ? AND receiver_id = ? AND donor_id = ?;") @@ -112,7 +199,7 @@ public void delete() { } /** - * Removes all reputations associated with the message + * Removes all reputations associated with the message. */ public void deleteAll() { query("DELETE FROM reputation_log WHERE message_id = ?") diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/ReputationRank.java b/src/main/java/de/chojo/repbot/dao/snapshots/ReputationRank.java index 937779d62..4c0120dfc 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/ReputationRank.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/ReputationRank.java @@ -20,7 +20,7 @@ import static de.chojo.sadu.queries.api.query.Query.query; /** - * Representing a repuration rank. + * Represents a reputation rank. *

* A rank is {@link Comparable} and will be sorted from the highest reputation to lowest. */ @@ -30,12 +30,27 @@ public class ReputationRank implements GuildHolder, Comparable { private final Ranks ranks; private Role role; + /** + * Constructs a ReputationRank object with the specified ranks, role ID, and reputation. + * + * @param ranks the ranks object + * @param roleId the role ID + * @param reputation the reputation value + */ public ReputationRank(Ranks ranks, long roleId, long reputation) { this.ranks = ranks; this.roleId = roleId; this.reputation = reputation; } + /** + * Builds a ReputationRank object from the specified ranks and database row. + * + * @param ranks the ranks object + * @param rs the database row + * @return the constructed ReputationRank object + * @throws SQLException if a database access error occurs + */ public static ReputationRank build(Ranks ranks, Row rs) throws SQLException { return new ReputationRank(ranks, rs.getLong("role_id"), @@ -43,6 +58,12 @@ public static ReputationRank build(Ranks ranks, Row rs) throws SQLException { ); } + /** + * Retrieves the role associated with this reputation rank for the specified guild. + * + * @param guild the guild + * @return an optional containing the role if found, otherwise an empty optional + */ public Optional getRole(Guild guild) { if (role == null) { role = guild.getRoleById(roleId); @@ -50,22 +71,37 @@ public Optional getRole(Guild guild) { return Optional.ofNullable(role); } + /** + * Returns the role ID associated with this reputation rank. + * + * @return the role ID + */ public long roleId() { return roleId; } + /** + * Returns the reputation value associated with this reputation rank. + * + * @return the reputation value + */ public long reputation() { return reputation; } + /** + * Retrieves the role associated with this reputation rank. + * + * @return an optional containing the role if found, otherwise an empty optional + */ public Optional role() { return getRole(ranks.guild()); } /** - * Remove a reputation role. + * Removes the reputation role from the database. * - * @return true + * @return true if the role was successfully removed, false otherwise */ public boolean remove() { var success = query("DELETE FROM guild_ranks WHERE guild_id = ? AND role_id = ?;") @@ -76,21 +112,42 @@ public boolean remove() { return success; } + /** + * Returns the guild associated with this reputation rank. + * + * @return the guild + */ @Override public Guild guild() { return ranks.guild(); } + /** + * Returns the guild ID associated with this reputation rank. + * + * @return the guild ID + */ @Override public long guildId() { return ranks.guildId(); } + /** + * Compares this reputation rank with another based on reputation. + * + * @param o the other reputation rank + * @return a negative integer, zero, or a positive integer as this reputation rank is less than, equal to, or greater than the specified reputation rank + */ @Override public int compareTo(@NotNull ReputationRank o) { return Long.compare(o.reputation, reputation); } + /** + * Returns a string representation of the reputation rank. + * + * @return a string representation of the reputation rank + */ @Override public String toString() { return "ReputationRank{" + diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/ResultEntry.java b/src/main/java/de/chojo/repbot/dao/snapshots/ResultEntry.java index 2d7a8c50d..cb594a025 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/ResultEntry.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/ResultEntry.java @@ -13,7 +13,22 @@ import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.MessageEmbed; +/** + * Represents an entry in the result snapshot. + * + * @param result the result snapshot + * @param channelId the ID of the channel + * @param messageId the ID of the message + */ public record ResultEntry(ResultSnapshot result, long channelId, long messageId) { + + /** + * Creates an embed message for the result entry. + * + * @param guild the guild + * @param context the event context + * @return the created message embed + */ public MessageEmbed embed(Guild guild, EventContext context) { var builder = new LocalizedEmbedBuilder(context.guildLocalizer()) .setAuthor("command.log.analyzer.message.author", diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/SubmitResultEntry.java b/src/main/java/de/chojo/repbot/dao/snapshots/SubmitResultEntry.java index ea3d73884..0f77f75f9 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/SubmitResultEntry.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/SubmitResultEntry.java @@ -9,5 +9,13 @@ import java.time.Instant; +/** + * Record representing an entry for a submit result. + * + * @param submitResult the result of the submission + * @param channelId the ID of the channel where the submission occurred + * @param messageId the ID of the message associated with the submission + * @param instant the timestamp when the submission was made + */ public record SubmitResultEntry(SubmitResult submitResult, long channelId, long messageId, Instant instant) { } diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/ResultSnapshot.java b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/ResultSnapshot.java index c777773cc..d1983bf77 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/ResultSnapshot.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/ResultSnapshot.java @@ -10,7 +10,18 @@ import de.chojo.repbot.dao.snapshots.ResultEntry; import net.dv8tion.jda.api.entities.Guild; +/** + * Interface for result snapshots. + * This interface is used to add result entries to a snapshot with a localized embed builder. + */ @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") public interface ResultSnapshot { + /** + * Adds a result entry to the snapshot. + * + * @param guild the guild where the result entry is being added + * @param entry the result entry to add + * @param builder the localized embed builder to use + */ void add(Guild guild, ResultEntry entry, LocalizedEmbedBuilder builder); } diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/AnswerResultSnapshot.java b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/AnswerResultSnapshot.java index 1e86259d4..9e6040248 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/AnswerResultSnapshot.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/AnswerResultSnapshot.java @@ -16,9 +16,20 @@ import java.util.List; +/** + * Snapshot class for storing the result of an answer match. + */ public class AnswerResultSnapshot extends DirectResultSnapshot implements ResultSnapshot { private final long messageId; + /** + * Constructs an AnswerResultSnapshot instance. + * + * @param donorId the ID of the donor + * @param match the match string + * @param receivers the list of receiver IDs + * @param messageId the ID of the message + */ @JsonCreator public AnswerResultSnapshot(@JsonProperty("donorId") long donorId, @JsonProperty("match") String match, @@ -28,6 +39,13 @@ public AnswerResultSnapshot(@JsonProperty("donorId") long donorId, this.messageId = messageId; } + /** + * Adds the result entry to the localized embed builder. + * + * @param guild the guild + * @param entry the result entry + * @param builder the localized embed builder + */ @Override public void add(Guild guild, ResultEntry entry, LocalizedEmbedBuilder builder) { super.add(guild, entry, builder); diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/DirectResultSnapshot.java b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/DirectResultSnapshot.java index 502f2167f..fee898a33 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/DirectResultSnapshot.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/DirectResultSnapshot.java @@ -17,9 +17,20 @@ import java.util.List; import java.util.stream.Collectors; +/** + * Represents a snapshot of a direct result match. + */ public class DirectResultSnapshot extends MatchResultSnapshot implements ResultSnapshot { private final List receivers; + /** + * Constructs a new DirectResultSnapshot. + * + * @param thankType the type of thank + * @param donorId the ID of the donor + * @param match the match string + * @param receivers the list of receiver IDs + */ @JsonCreator public DirectResultSnapshot(@JsonProperty("thankType") ThankType thankType, @JsonProperty("donorId") long donorId, @@ -29,10 +40,22 @@ public DirectResultSnapshot(@JsonProperty("thankType") ThankType thankType, this.receivers = receivers; } + /** + * Retrieves the list of receiver IDs. + * + * @return the list of receiver IDs + */ public List receivers() { return receivers; } + /** + * Adds the result entry to the localized embed builder. + * + * @param guild the guild + * @param entry the result entry + * @param builder the localized embed builder + */ @Override public void add(Guild guild, ResultEntry entry, LocalizedEmbedBuilder builder) { super.add(guild, entry, builder); diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/FuzzyResultSnapshot.java b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/FuzzyResultSnapshot.java index b6b859d01..a68ad0d5d 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/FuzzyResultSnapshot.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/FuzzyResultSnapshot.java @@ -18,10 +18,21 @@ import java.util.List; import java.util.stream.Collectors; +/** + * Represents a snapshot of fuzzy match results. + */ public class FuzzyResultSnapshot extends MatchResultSnapshot implements ResultSnapshot { private final List thankwords; private final List memberMatches; + /** + * Constructs a new FuzzyResultSnapshot instance. + * + * @param donor the ID of the donor + * @param match the match string + * @param thankwords the list of thank words + * @param memberMatches the list of member matches + */ @JsonCreator public FuzzyResultSnapshot(@JsonProperty("donor") long donor, @JsonProperty("match") String match, @@ -32,6 +43,13 @@ public FuzzyResultSnapshot(@JsonProperty("donor") long donor, this.memberMatches = memberMatches; } + /** + * Adds the result entry to the localized embed builder. + * + * @param guild the guild + * @param entry the result entry + * @param builder the localized embed builder + */ @Override public void add(Guild guild, ResultEntry entry, LocalizedEmbedBuilder builder) { super.add(guild, entry, builder); diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/MatchResultSnapshot.java b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/MatchResultSnapshot.java index 46b040cd9..903e18202 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/MatchResultSnapshot.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/analyzer/match/MatchResultSnapshot.java @@ -13,29 +13,61 @@ import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.User; +/** + * Abstract class representing a snapshot of a match result. + */ public abstract class MatchResultSnapshot implements ResultSnapshot { private final ThankType thankType; private final long donorId; private final String match; + /** + * Constructs a new MatchResultSnapshot with the specified thank type, donor ID, and match. + * + * @param thankType the type of thank + * @param donorId the ID of the donor + * @param match the matched string + */ public MatchResultSnapshot(ThankType thankType, long donorId, String match) { this.thankType = thankType; this.donorId = donorId; this.match = match; } + /** + * Returns the type of thank. + * + * @return the thank type + */ public ThankType thankType() { return thankType; } + /** + * Returns the ID of the donor. + * + * @return the donor ID + */ public long donorId() { return donorId; } + /** + * Returns the matched string. + * + * @return the match + */ public String match() { return match; } + /** + * Adds the match result information to the provided LocalizedEmbedBuilder. + * + * @param guild the guild + * @param entry the result entry + * @param builder the LocalizedEmbedBuilder to add information to + */ @Override public void add(Guild guild, ResultEntry entry, LocalizedEmbedBuilder builder) { builder.setTitle(thankType.nameLocaleKey()) diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/ChartProvider.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/ChartProvider.java index 29ea9001d..6af770ea6 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/ChartProvider.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/ChartProvider.java @@ -5,7 +5,16 @@ */ package de.chojo.repbot.dao.snapshots.statistics; +/** + * Interface for providing chart data. + */ public interface ChartProvider { + /** + * Generates a chart with the specified title. + * + * @param title the title of the chart + * @return a byte array representing the chart + */ byte[] getChart(String title); } diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CommandStatistic.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CommandStatistic.java index 11ae30126..2a696f266 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CommandStatistic.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CommandStatistic.java @@ -5,14 +5,28 @@ */ package de.chojo.repbot.dao.snapshots.statistics; - import de.chojo.sadu.mapper.wrapper.Row; import java.sql.SQLException; import java.time.LocalDate; +/** + * Record class representing a command statistic. + * + * @param date the date of the statistic + * @param command the command name + * @param count the count of the command executions + */ public record CommandStatistic(LocalDate date, String command, int count) { + /** + * Builds a CommandStatistic instance from a database row. + * + * @param rs the database row + * @param dateKey the key for the date column + * @return a CommandStatistic instance + * @throws SQLException if a database access error occurs + */ public static CommandStatistic build(Row rs, String dateKey) throws SQLException { return new CommandStatistic(rs.getDate(dateKey).toLocalDate(), rs.getString("command"), diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CommandsStatistic.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CommandsStatistic.java index 1cb103d25..e35740b59 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CommandsStatistic.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CommandsStatistic.java @@ -14,8 +14,20 @@ import java.time.LocalDate; import java.util.List; +/** + * Represents the statistics of commands executed on a specific date. + * + * @param date the date of the statistics + * @param commands the list of command statistics + */ public record CommandsStatistic(LocalDate date, List commands) implements ChartProvider { + /** + * Generates a chart representing the command statistics. + * + * @param title the title of the chart + * @return a byte array containing the chart image in PNG format + */ @Override public byte[] getChart(String title) { var categorySeries = new CategoryChartBuilder().width(1200).height(600) diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CountStatistics.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CountStatistics.java index abbdbbb4e..72d457e62 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CountStatistics.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CountStatistics.java @@ -11,17 +11,45 @@ import java.sql.SQLException; import java.time.LocalDateTime; +/** + * Represents a count statistic with a date and count value. + * + * @param date the date of the statistic + * @param count the count value of the statistic + */ public record CountStatistics(LocalDateTime date, int count) implements Comparable { + /** + * Builds a CountStatistics instance from a database row using the specified date key. + * + * @param rs the database row + * @param dateKey the key for the date column + * @return a new CountStatistics instance + * @throws SQLException if a database access error occurs + */ public static CountStatistics build(Row rs, String dateKey) throws SQLException { return build(rs, "count", dateKey); } + /** + * Builds a CountStatistics instance from a database row using the specified count and date keys. + * + * @param rs the database row + * @param countKey the key for the count column + * @param dateKey the key for the date column + * @return a new CountStatistics instance + * @throws SQLException if a database access error occurs + */ public static CountStatistics build(Row rs, String countKey, String dateKey) throws SQLException { - return new CountStatistics(rs.getTimestamp(dateKey).toLocalDateTime(), - rs.getInt(countKey)); + return new CountStatistics(rs.getTimestamp(dateKey).toLocalDateTime(), rs.getInt(countKey)); } + /** + * Compares this CountStatistics instance with another based on the date. + * + * @param o the other CountStatistics instance + * @return a negative integer, zero, or a positive integer as this instance is less than, equal to, or greater than the specified instance + */ @Override public int compareTo(@NotNull CountStatistics o) { return date().compareTo(o.date()); diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CountsStatistic.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CountsStatistic.java index ab9223811..c1091167d 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CountsStatistic.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/CountsStatistic.java @@ -17,9 +17,19 @@ import java.util.Date; import java.util.List; +/** + * Represents a statistic of counts over time and provides a method to generate a chart. + * + * @param stats the list of count statistics + */ public record CountsStatistic(List stats) implements ChartProvider { - + /** + * Gets the count statistics at the specified index. + * + * @param index the index of the count statistics + * @return the count statistics at the specified index, or a default value if the list is empty + */ public CountStatistics get(int index) { if (stats.isEmpty()) { return new CountStatistics(LocalDateTime.MIN, 0); @@ -27,6 +37,12 @@ public CountStatistics get(int index) { return stats.get(index); } + /** + * Generates a chart representing the count statistics. + * + * @param title the title of the chart + * @return a byte array representing the chart in PNG format + */ @Override public byte[] getChart(String title) { var categorySeries = new XYChartBuilder().width(1200).height(600) @@ -58,6 +74,12 @@ public byte[] getChart(String title) { } } + /** + * Converts a LocalDateTime to a Date object. + * + * @param date the LocalDateTime to convert + * @return the corresponding Date object + */ private Date toDate(LocalDateTime date) { return new Date(date.toEpochSecond(ZoneOffset.UTC) * 1000); } diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/DowStatistics.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/DowStatistics.java index 511db41a6..d3ab1bcc9 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/DowStatistics.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/DowStatistics.java @@ -11,18 +11,44 @@ import java.sql.SQLException; import java.time.LocalDate; +/** + * Represents the statistics for a specific day of the week. + * + * @param date the date of the statistics + * @param dow the day of the week (1 for Monday, 2 for Tuesday, etc.) + * @param count the count of occurrences on that day + */ public record DowStatistics(LocalDate date, int dow, int count) implements Comparable { + /** + * Builds a DowStatistics instance from a database row. + * + * @param rs the database row + * @param dateKey the key for the date column + * @return a new DowStatistics instance + * @throws SQLException if a database access error occurs + */ public static DowStatistics build(Row rs, String dateKey) throws SQLException { return new DowStatistics(rs.getDate(dateKey).toLocalDate(), rs.getInt("dow"), rs.getInt("count")); } + /** + * Compares this DowStatistics instance with another based on the date. + * + * @param o the other DowStatistics instance + * @return a negative integer, zero, or a positive integer as this instance is less than, equal to, or greater than the specified object + */ @Override public int compareTo(@NotNull DowStatistics o) { return date().compareTo(o.date()); } + /** + * Converts the day of the week to its string representation. + * + * @return the string representation of the day of the week + */ public String dowAsString() { return switch (dow()) { case 1 -> "Monday"; diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/DowsStatistic.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/DowsStatistic.java index 5d0c9afa3..a9d4ce153 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/DowsStatistic.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/DowsStatistic.java @@ -21,8 +21,19 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +/** + * Represents statistics for days of the week. + * + * @param stats the list of day of the week statistics + */ public record DowsStatistic(List stats) implements ChartProvider { + /** + * Generates a chart based on the statistics. + * + * @param title the title of the chart + * @return a byte array representing the chart image + */ @Override public byte[] getChart(String title) { var categorySeries = new CategoryChartBuilder().width(1200).height(600) @@ -65,6 +76,11 @@ public byte[] getChart(String title) { } } + /** + * Gets the date of the previous Monday. + * + * @return the date of the previous Monday + */ private LocalDate getMonday() { return LocalDate.now().with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); } diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/LabeledCountStatistic.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/LabeledCountStatistic.java index 924a012e6..ba487004b 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/LabeledCountStatistic.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/LabeledCountStatistic.java @@ -19,8 +19,19 @@ import java.util.List; import java.util.Map; +/** + * Represents a labeled count statistic and provides chart generation functionality. + * + * @param stats a map containing labels and their corresponding list of CountStatistics + */ public record LabeledCountStatistic(Map> stats) implements ChartProvider { + /** + * Generates a chart with the given title. + * + * @param title the title of the chart + * @return a byte array representing the chart in PNG format + */ @Override public byte[] getChart(String title) { var categorySeries = new XYChartBuilder().width(1200).height(600) @@ -52,6 +63,12 @@ public byte[] getChart(String title) { } } + /** + * Converts a LocalDateTime to a Date. + * + * @param date the LocalDateTime to convert + * @return the corresponding Date + */ private Date toDate(LocalDateTime date) { return new Date(date.toEpochSecond(ZoneOffset.UTC) * 1000); } diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/UserStatistic.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/UserStatistic.java index 0f5746a44..0e32d1f22 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/UserStatistic.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/UserStatistic.java @@ -11,12 +11,35 @@ import java.sql.SQLException; import java.time.LocalDate; +/** + * Record representing user statistics. + * + * @param date the date of the statistics + * @param donors the number of donors + * @param receivers the number of receivers + * @param total the total count + */ public record UserStatistic(LocalDate date, int donors, int receivers, int total) implements Comparable { + + /** + * Builds a UserStatistic instance from a database row. + * + * @param rs the database row + * @param dateKey the key for the date column + * @return the created UserStatistic instance + * @throws SQLException if a database access error occurs + */ public static UserStatistic build(Row rs, String dateKey) throws SQLException { return new UserStatistic(rs.getDate(dateKey).toLocalDate(), rs.getInt("donor_count"), rs.getInt("receiver_count"), rs.getInt("total_count")); } + /** + * Compares this UserStatistic to another based on the date. + * + * @param o the other UserStatistic to compare to + * @return a negative integer, zero, or a positive integer as this UserStatistic is less than, equal to, or greater than the specified UserStatistic + */ @Override public int compareTo(@NotNull UserStatistic o) { return date().compareTo(o.date()); diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/UsersStatistic.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/UsersStatistic.java index a5d879c20..538b2071c 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/UsersStatistic.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/UsersStatistic.java @@ -18,8 +18,19 @@ import java.util.Date; import java.util.List; +/** + * Record for storing user statistics and providing chart generation. + * + * @param stats the list of user statistics + */ public record UsersStatistic(List stats) implements ChartProvider { + /** + * Generates a chart image based on the user statistics. + * + * @param title the title of the chart + * @return a byte array representing the chart image in PNG format + */ @Override public byte[] getChart(String title) { var categorySeries = new XYChartBuilder().width(1200).height(600) @@ -55,7 +66,6 @@ public byte[] getChart(String title) { .setMarker(SeriesMarkers.NONE) .setLabel("Receivers"); - try { return BitmapEncoder.getBitmapBytes(categorySeries, BitmapEncoder.BitmapFormat.PNG); } catch (IOException e) { @@ -63,6 +73,12 @@ public byte[] getChart(String title) { } } + /** + * Converts a LocalDate to a Date object. + * + * @param date the LocalDate to convert + * @return the corresponding Date object + */ private Date toDate(LocalDate date) { return new Date(date.atStartOfDay().toEpochSecond(ZoneOffset.UTC) * 1000); } diff --git a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/builder/LabeledCountStatisticBuilder.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/builder/LabeledCountStatisticBuilder.java index 0c79e46bc..b63b3e0be 100644 --- a/src/main/java/de/chojo/repbot/dao/snapshots/statistics/builder/LabeledCountStatisticBuilder.java +++ b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/builder/LabeledCountStatisticBuilder.java @@ -13,14 +13,35 @@ import java.util.List; import java.util.Map; +/** + * Builder class for creating LabeledCountStatistic instances. + */ public class LabeledCountStatisticBuilder { private final Map> stats = new LinkedHashMap<>(); + /** + * Creates a new LabeledCountStatisticBuilder instance. + */ + public LabeledCountStatisticBuilder(){ + } + + /** + * Adds a CountStatistics instance to the builder with the specified label. + * + * @param label the label for the statistics + * @param statistic the CountStatistics instance to add + * @return the current instance of LabeledCountStatisticBuilder + */ public LabeledCountStatisticBuilder add(String label, CountStatistics statistic) { stats.computeIfAbsent(label, key -> new ArrayList<>()).add(statistic); return this; } + /** + * Builds and returns a LabeledCountStatistic instance with the accumulated statistics. + * + * @return a new LabeledCountStatistic instance + */ public LabeledCountStatistic build() { return new LabeledCountStatistic(stats); } diff --git a/src/main/java/de/chojo/repbot/listener/LogListener.java b/src/main/java/de/chojo/repbot/listener/LogListener.java index 3ede75d1c..fab311d95 100644 --- a/src/main/java/de/chojo/repbot/listener/LogListener.java +++ b/src/main/java/de/chojo/repbot/listener/LogListener.java @@ -29,6 +29,9 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Listener for logging various events related to guilds and sessions. + */ public class LogListener extends ListenerAdapter implements Runnable { private static final Logger log = getLogger(LogListener.class); private final Map disconnected = new HashMap<>(); @@ -36,12 +39,23 @@ public class LogListener extends ListenerAdapter implements Runnable { private LogListener() { } + /** + * Creates a new LogListener and schedules it to run at a fixed rate. + * + * @param service the ScheduledExecutorService to use for scheduling + * @return a new LogListener instance + */ public static LogListener create(ScheduledExecutorService service) { var logListener = new LogListener(); service.scheduleAtFixedRate(logListener, 60, 60, TimeUnit.SECONDS); return logListener; } + /** + * Handles the event when the bot joins a guild. + * + * @param event the GuildJoinEvent + */ @Override public void onGuildJoin(@Nonnull GuildJoinEvent event) { log.info(LogNotify.STATUS, "RepBot joined guild {} on shard {}.", @@ -49,6 +63,11 @@ public void onGuildJoin(@Nonnull GuildJoinEvent event) { event.getJDA().getShardInfo().getShardId()); } + /** + * Handles the event when the bot leaves a guild. + * + * @param event the GuildLeaveEvent + */ @Override public void onGuildLeave(@Nonnull GuildLeaveEvent event) { log.info(LogNotify.STATUS, "RepBot left guild {} on shard {}.", @@ -56,22 +75,42 @@ public void onGuildLeave(@Nonnull GuildLeaveEvent event) { event.getJDA().getShardInfo().getShardId()); } + /** + * Handles the event when a session disconnects. + * + * @param event the SessionDisconnectEvent + */ @Override public void onSessionDisconnect(@NotNull SessionDisconnectEvent event) { disconnected.put(event.getJDA().getShardInfo().getShardId(), Instant.now()); log.debug("Shard {} disconnected.", event.getJDA().getShardInfo().getShardId()); } + /** + * Handles the event when a session is recreated. + * + * @param event the SessionRecreateEvent + */ @Override public void onSessionRecreate(@NotNull SessionRecreateEvent event) { handleShardReconnect(event.getJDA()); } + /** + * Handles the event when a session resumes. + * + * @param event the SessionResumeEvent + */ @Override public void onSessionResume(@NotNull SessionResumeEvent event) { handleShardReconnect(event.getJDA()); } + /** + * Handles shard reconnection logic. + * + * @param jda the JDA instance + */ private void handleShardReconnect(JDA jda) { var shardId = jda.getShardInfo().getShardId(); var seconds = Duration.between( @@ -87,6 +126,11 @@ private void handleShardReconnect(JDA jda) { } } + /** + * Handles the event when the bot is ready. + * + * @param event the ReadyEvent + */ @Override public void onReady(@Nonnull ReadyEvent event) { handleShardReconnect(event.getJDA()); @@ -96,6 +140,9 @@ public void onReady(@Nonnull ReadyEvent event) { event.getGuildTotalCount()); } + /** + * Periodically checks for disconnected shards and logs a warning if any are found. + */ @Override public void run() { if (disconnected.isEmpty()) return; diff --git a/src/main/java/de/chojo/repbot/listener/MessageListener.java b/src/main/java/de/chojo/repbot/listener/MessageListener.java index 276211c95..8bbe05a92 100644 --- a/src/main/java/de/chojo/repbot/listener/MessageListener.java +++ b/src/main/java/de/chojo/repbot/listener/MessageListener.java @@ -43,7 +43,13 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Listener for handling various message-related events. + */ public class MessageListener extends ListenerAdapter { + /** + * Logger instance for logging events. + */ private static final Logger log = getLogger(MessageListener.class); private final ILocalizer localizer; private final Configuration configuration; @@ -54,6 +60,18 @@ public class MessageListener extends ListenerAdapter { private final ContextResolver contextResolver; private final MessageAnalyzer messageAnalyzer; + /** + * Constructs a new MessageListener. + * + * @param localizer the localizer instance + * @param configuration the configuration instance + * @param guilds the guilds provider + * @param repBotCachePolicy the cache policy + * @param reputationVoteListener the reputation vote listener + * @param reputationService the reputation service + * @param contextResolver the context resolver + * @param messageAnalyzer the message analyzer + */ public MessageListener(ILocalizer localizer, Configuration configuration, Guilds guilds, RepBotCachePolicy repBotCachePolicy, ReputationVoteListener reputationVoteListener, ReputationService reputationService, ContextResolver contextResolver, MessageAnalyzer messageAnalyzer) { @@ -67,6 +85,11 @@ public MessageListener(ILocalizer localizer, Configuration configuration, Guilds this.messageAnalyzer = messageAnalyzer; } + /** + * Handles the channel creation event. + * + * @param event the channel creation event + */ @Override public void onChannelCreate(@NotNull ChannelCreateEvent event) { if (event.getChannelType() == ChannelType.GUILD_PUBLIC_THREAD) { @@ -78,6 +101,11 @@ public void onChannelCreate(@NotNull ChannelCreateEvent event) { } } + /** + * Handles the message deletion event. + * + * @param event the message deletion event + */ @Override public void onMessageDelete(@NotNull MessageDeleteEvent event) { guilds.guild(event.getGuild()).reputation().log() @@ -85,6 +113,11 @@ public void onMessageDelete(@NotNull MessageDeleteEvent event) { .ifPresent(ReputationLogEntry::deleteAll); } + /** + * Handles the bulk message deletion event. + * + * @param event the bulk message deletion event + */ @Override public void onMessageBulkDelete(@NotNull MessageBulkDeleteEvent event) { var reputationLog = guilds.guild(event.getGuild()).reputation().log(); @@ -95,6 +128,11 @@ public void onMessageBulkDelete(@NotNull MessageBulkDeleteEvent event) { .forEach(ReputationLogEntry::deleteAll); } + /** + * Handles the message received event. + * + * @param event the message received event + */ @Override public void onMessageReceived(@NotNull MessageReceivedEvent event) { if (event.getAuthor().isBot() || event.isWebhookMessage() || !event.isFromGuild()) return; @@ -183,6 +221,12 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { } } + /** + * Resolves the case when no target is found for the reputation submission. + * + * @param message the message + * @param settings the settings + */ private void resolveNoTarget(Message message, Settings settings) { log.trace("Resolving missing target for {}", message.getIdLong()); var recentMembers = new LinkedHashSet<>(contextResolver.getCombinedContext(message, settings).members()); diff --git a/src/main/java/de/chojo/repbot/listener/ReactionListener.java b/src/main/java/de/chojo/repbot/listener/ReactionListener.java index 3757468b4..5ada1e912 100644 --- a/src/main/java/de/chojo/repbot/listener/ReactionListener.java +++ b/src/main/java/de/chojo/repbot/listener/ReactionListener.java @@ -40,6 +40,9 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Listener for handling message reaction events in a guild. + */ public class ReactionListener extends ListenerAdapter { private static final int REACTION_COOLDOWN = 30; private static final Logger log = getLogger(ReactionListener.class); @@ -50,6 +53,14 @@ public class ReactionListener extends ListenerAdapter { private final Cache lastReaction = CacheBuilder.newBuilder().expireAfterAccess(60, TimeUnit.SECONDS) .build(); + /** + * Constructs a ReactionListener. + * + * @param guilds the guilds provider + * @param localizer the localizer for localization + * @param reputationService the reputation service + * @param configuration the configuration settings + */ public ReactionListener(Guilds guilds, ILocalizer localizer, ReputationService reputationService, Configuration configuration) { this.guilds = guilds; this.localizer = localizer; @@ -57,6 +68,11 @@ public ReactionListener(Guilds guilds, ILocalizer localizer, ReputationService r this.configuration = configuration; } + /** + * Handles the event when a reaction is added to a message. + * + * @param event the message reaction add event + */ @Override public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) { if (event.getUser().isBot() || !event.isFromGuild()) return; @@ -118,7 +134,11 @@ public void onMessageReactionAdd(@NotNull MessageReactionAddEvent event) { } } - + /** + * Handles the event when a reaction emoji is removed from a message. + * + * @param event the message reaction remove emoji event + */ @Override public void onMessageReactionRemoveEmoji(@NotNull MessageReactionRemoveEmojiEvent event) { if (!event.isFromGuild()) return; @@ -129,6 +149,11 @@ public void onMessageReactionRemoveEmoji(@NotNull MessageReactionRemoveEmojiEven .forEach(ReputationLogEntry::delete); } + /** + * Handles the event when a reaction is removed from a message. + * + * @param event the message reaction remove event + */ @Override public void onMessageReactionRemove(@NotNull MessageReactionRemoveEvent event) { if (!event.isFromGuild()) return; @@ -147,6 +172,11 @@ public void onMessageReactionRemove(@NotNull MessageReactionRemoveEvent event) { } } + /** + * Handles the event when all reactions are removed from a message. + * + * @param event the message reaction remove all event + */ @Override public void onMessageReactionRemoveAll(@NotNull MessageReactionRemoveAllEvent event) { guilds.guild(event.getGuild()).reputation().log().messageLog(event.getMessageIdLong(), 50).stream() @@ -154,6 +184,12 @@ public void onMessageReactionRemoveAll(@NotNull MessageReactionRemoveAllEvent ev .forEach(ReputationLogEntry::delete); } + /** + * Checks if the member is on cooldown for reacting. + * + * @param member the member to check + * @return true if the member is on cooldown, false otherwise + */ public boolean isCooldown(Member member) { try { return lastReaction.get(member.getIdLong(), () -> Instant.MIN) @@ -164,6 +200,11 @@ public boolean isCooldown(Member member) { return true; } + /** + * Records the time when the member reacted. + * + * @param member the member who reacted + */ public void reacted(Member member) { lastReaction.put(member.getIdLong(), Instant.now()); } diff --git a/src/main/java/de/chojo/repbot/listener/StateListener.java b/src/main/java/de/chojo/repbot/listener/StateListener.java index 128bdb8f7..517349b94 100644 --- a/src/main/java/de/chojo/repbot/listener/StateListener.java +++ b/src/main/java/de/chojo/repbot/listener/StateListener.java @@ -27,13 +27,27 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Listener for handling various state events in the bot. + */ public class StateListener extends ListenerAdapter { + /** + * Logger for logging events. + */ private static final Logger log = getLogger(StateListener.class); private final Guilds guilds; private final ILocalizer localizer; private final Configuration configuration; private final Metrics metrics; + /** + * Constructs a new StateListener instance. + * + * @param guilds the guilds provider + * @param localizer the localizer for localization + * @param configuration the bot configuration + * @param metrics the metrics provider + */ private StateListener(Guilds guilds, ILocalizer localizer, Configuration configuration, Metrics metrics) { this.guilds = guilds; this.localizer = localizer; @@ -41,15 +55,34 @@ private StateListener(Guilds guilds, ILocalizer localizer, Configuration configu this.metrics = metrics; } + /** + * Handles generic interaction creation events. + * + * @param event the generic interaction create event + */ @Override public void onGenericInteractionCreate(@NotNull GenericInteractionCreateEvent event) { metrics.service().countInteraction(); } + /** + * Creates a new StateListener instance. + * + * @param localizer the localizer for localization + * @param guilds the guilds provider + * @param configuration the bot configuration + * @param metrics the metrics provider + * @return a new StateListener instance + */ public static StateListener of(ILocalizer localizer, Guilds guilds, Configuration configuration, Metrics metrics) { return new StateListener(guilds, localizer, configuration, metrics); } + /** + * Handles guild join events. + * + * @param event the guild join event + */ @Override public void onGuildJoin(@NotNull GuildJoinEvent event) { guilds.guild(event.getGuild()).gdpr().dequeueDeletion(); @@ -67,34 +100,64 @@ public void onGuildJoin(@NotNull GuildJoinEvent event) { } } + /** + * Handles guild leave events. + * + * @param event the guild leave event + */ @Override public void onGuildLeave(@NotNull GuildLeaveEvent event) { // We want to delete all data of a guild after the bot left. guilds.guild(event.getGuild()).gdpr().queueDeletion(); } + /** + * Handles guild member join events. + * + * @param event the guild member join event + */ @Override public void onGuildMemberJoin(@NotNull GuildMemberJoinEvent event) { // We want to abort deletion of user data if a user rejoins a guild during grace period guilds.guild(event.getGuild()).reputation().user(event.getMember()).gdpr().dequeueDeletion(); } + /** + * Handles guild member remove events. + * + * @param event the guild member remove event + */ @Override public void onGuildMemberRemove(@NotNull GuildMemberRemoveEvent event) { // When a user leaves a guild, there is no reason for us to keep their data. guilds.guild(event.getGuild()).reputation().user(event.getUser()).gdpr().queueDeletion(); } + /** + * Handles role delete events. + * + * @param event the role delete event + */ @Override public void onRoleDelete(@NotNull RoleDeleteEvent event) { guilds.guild(event.getGuild()).settings().ranks().rank(event.getRole()).ifPresent(ReputationRank::remove); } + /** + * Handles channel delete events. + * + * @param event the channel delete event + */ @Override public void onChannelDelete(@NotNull ChannelDeleteEvent event) { guilds.guild(event.getGuild()).settings().thanking().channels().remove(event.getChannel()); } + /** + * Handles emoji removed events. + * + * @param event the emoji removed event + */ @Override public void onEmojiRemoved(@NotNull EmojiRemovedEvent event) { var guildSettings = guilds.guild(event.getGuild()).settings(); diff --git a/src/main/java/de/chojo/repbot/listener/VoiceStateListener.java b/src/main/java/de/chojo/repbot/listener/VoiceStateListener.java index 47c43d89a..be4e1b6a9 100644 --- a/src/main/java/de/chojo/repbot/listener/VoiceStateListener.java +++ b/src/main/java/de/chojo/repbot/listener/VoiceStateListener.java @@ -13,19 +13,39 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +/** + * Listener for voice state updates in a guild. + */ public class VoiceStateListener extends ListenerAdapter implements Runnable { private final Voice voice; + /** + * Constructs a new VoiceStateListener. + * + * @param voice the voice data provider + */ public VoiceStateListener(Voice voice) { this.voice = voice; } + /** + * Creates a new VoiceStateListener and schedules it to run at fixed intervals. + * + * @param voice the voice data provider + * @param repBotWorker the scheduled executor service + * @return the created VoiceStateListener + */ public static VoiceStateListener of(Voice voice, ScheduledExecutorService repBotWorker) { var voiceStateListener = new VoiceStateListener(voice); repBotWorker.scheduleAtFixedRate(voiceStateListener, 2, 12, TimeUnit.HOURS); return voiceStateListener; } + /** + * Handles the event when a member updates their voice state in a guild. + * + * @param event the guild voice update event + */ @Override public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) { if (event.getChannelLeft() != null) { @@ -33,6 +53,9 @@ public void onGuildVoiceUpdate(@NotNull GuildVoiceUpdateEvent event) { } } + /** + * Runs the cleanup process for voice data. + */ @Override public void run() { voice.cleanup(); diff --git a/src/main/java/de/chojo/repbot/listener/voting/ReputationVoteListener.java b/src/main/java/de/chojo/repbot/listener/voting/ReputationVoteListener.java index 8de959812..4a5d40229 100644 --- a/src/main/java/de/chojo/repbot/listener/voting/ReputationVoteListener.java +++ b/src/main/java/de/chojo/repbot/listener/voting/ReputationVoteListener.java @@ -43,6 +43,9 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; +/** + * Listener for handling reputation vote interactions. + */ public class ReputationVoteListener extends ListenerAdapter { private static final ActionComponent DELETE = Button.of(ButtonStyle.DANGER, "vote:delete", Emoji.fromUnicode("🗑️")); private static final Pattern VOTE = Pattern.compile("vote:(?\\d*?)"); @@ -52,6 +55,14 @@ public class ReputationVoteListener extends ListenerAdapter { private final Configuration configuration; private final Map voteRequests = new HashMap<>(); + /** + * Constructs a new ReputationVoteListener. + * + * @param guilds the guilds provider + * @param reputationService the reputation service + * @param localizer the localizer + * @param configuration the configuration + */ public ReputationVoteListener(Guilds guilds, ReputationService reputationService, ILocalizer localizer, Configuration configuration) { this.guilds = guilds; this.reputationService = reputationService; @@ -59,6 +70,11 @@ public ReputationVoteListener(Guilds guilds, ReputationService reputationService this.configuration = configuration; } + /** + * Handles button interaction events. + * + * @param event the button interaction event + */ @Override public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { if (!voteRequests.containsKey(event.getMessageIdLong())) return; @@ -109,6 +125,13 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { } } + /** + * Registers a vote request. + * + * @param message the message + * @param members the list of members + * @param settings the settings + */ public void registerVote(Message message, List members, Settings settings) { if (PermissionErrorHandler.assertAndHandle(message.getGuildChannel(), loc.context(LocaleProvider.guild(message.getGuild())), configuration, Permission.MESSAGE_SEND, Permission.MESSAGE_EMBED_LINKS)) { return; @@ -159,7 +182,12 @@ public void registerVote(Message message, List members, Settings setting }); } - + /** + * Creates a list of action rows from the given components. + * + * @param components the list of action components + * @return the list of action rows + */ private List getComponentRows(List components) { var comp = new ArrayList<>(components); comp.add(DELETE); diff --git a/src/main/java/de/chojo/repbot/listener/voting/VoteComponent.java b/src/main/java/de/chojo/repbot/listener/voting/VoteComponent.java index 5880d02c5..bb3a3dac7 100644 --- a/src/main/java/de/chojo/repbot/listener/voting/VoteComponent.java +++ b/src/main/java/de/chojo/repbot/listener/voting/VoteComponent.java @@ -8,6 +8,11 @@ import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.interactions.components.ActionComponent; - +/** + * Record representing a vote component. + * + * @param member the member associated with the vote component + * @param component the action component for the vote + */ public record VoteComponent(Member member, ActionComponent component) { } diff --git a/src/main/java/de/chojo/repbot/listener/voting/VoteRequest.java b/src/main/java/de/chojo/repbot/listener/voting/VoteRequest.java index c101a6514..cbdd3060f 100644 --- a/src/main/java/de/chojo/repbot/listener/voting/VoteRequest.java +++ b/src/main/java/de/chojo/repbot/listener/voting/VoteRequest.java @@ -15,6 +15,9 @@ import java.util.Map; import java.util.Optional; +/** + * Class representing a vote request. + */ public class VoteRequest { private final Member member; private final LocalizedEmbedBuilder embedBuilder; @@ -23,6 +26,16 @@ public class VoteRequest { private final Map voteTargets; private int remainingVotes; + /** + * Constructs a new VoteRequest. + * + * @param member the member initiating the vote + * @param embedBuilder the embed builder for creating message embeds + * @param voteMessage the message containing the vote + * @param refMessage the reference message + * @param voteTargets the map of vote targets + * @param remainingVotes the number of remaining votes + */ public VoteRequest(Member member, LocalizedEmbedBuilder embedBuilder, Message voteMessage, Message refMessage, Map voteTargets, int remainingVotes) { this.member = member; this.embedBuilder = embedBuilder; @@ -32,50 +45,110 @@ public VoteRequest(Member member, LocalizedEmbedBuilder embedBuilder, Message vo this.remainingVotes = remainingVotes; } + /** + * Retrieves the target member for the given ID. + * + * @param id the ID of the vote target + * @return an Optional containing the target member if present, otherwise an empty Optional + */ public Optional getTarget(String id) { return Optional.ofNullable(voteTargets.get(id).member()); } + /** + * Decrements the remaining votes count. + */ public void voted() { remainingVotes--; } + /** + * Creates a new message embed with the given description. + * + * @param description the description for the embed + * @return the created MessageEmbed + */ public MessageEmbed getNewEmbed(String description) { return embedBuilder.setDescription(description).build(); } + /** + * Retrieves the member initiating the vote. + * + * @return the member initiating the vote + */ public Member member() { return member; } + /** + * Retrieves the embed builder. + * + * @return the embed builder + */ public LocalizedEmbedBuilder embedBuilder() { return embedBuilder; } + /** + * Retrieves the vote message. + * + * @return the vote message + */ public Message voteMessage() { return voteMessage; } + /** + * Retrieves the reference message. + * + * @return the reference message + */ public Message refMessage() { return refMessage; } + /** + * Retrieves the map of vote targets. + * + * @return the map of vote targets + */ public Map voteTargets() { return voteTargets; } + /** + * Retrieves the list of action components for the vote targets. + * + * @return the list of action components + */ public List components() { return voteTargets.values().stream().map(VoteComponent::component).toList(); } + /** + * Retrieves the number of remaining votes. + * + * @return the number of remaining votes + */ public int remainingVotes() { return remainingVotes; } + /** + * Removes a vote target by ID. + * + * @param id the ID of the vote target to remove + */ public void remove(String id) { voteTargets.remove(id); } + /** + * Checks if the member can still vote. + * + * @return true if the member can still vote, false otherwise + */ public boolean canVote() { return remainingVotes > 0; } diff --git a/src/main/java/de/chojo/repbot/serialization/ThankwordsContainer.java b/src/main/java/de/chojo/repbot/serialization/ThankwordsContainer.java index 0b1c80126..dff913a53 100644 --- a/src/main/java/de/chojo/repbot/serialization/ThankwordsContainer.java +++ b/src/main/java/de/chojo/repbot/serialization/ThankwordsContainer.java @@ -11,10 +11,24 @@ import java.util.Map; import java.util.Set; +/** + * Container class for managing thank words. + */ @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) public class ThankwordsContainer { private Map> defaults = new HashMap<>(); + /** + * Creates a new container with the default thank words. + */ + public ThankwordsContainer(){ + } + /** + * Retrieves the list of thank words for the given key. + * + * @param key the key to look up + * @return the list of thank words, or null if the key is not found + */ public List get(String key) { for (var entry : defaults.entrySet()) { if (entry.getKey().equalsIgnoreCase(key)) { @@ -24,6 +38,11 @@ public List get(String key) { return null; } + /** + * Retrieves the set of available languages. + * + * @return an unmodifiable set of available languages + */ public Set getAvailableLanguages() { return Collections.unmodifiableSet(defaults.keySet()); } diff --git a/src/main/java/de/chojo/repbot/service/AnalyzerService.java b/src/main/java/de/chojo/repbot/service/AnalyzerService.java index 76874e76b..302255e65 100644 --- a/src/main/java/de/chojo/repbot/service/AnalyzerService.java +++ b/src/main/java/de/chojo/repbot/service/AnalyzerService.java @@ -5,24 +5,40 @@ */ package de.chojo.repbot.service; -import de.chojo.repbot.config.Configuration; import de.chojo.repbot.dao.access.Analyzer; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +/** + * Service for running the analyzer at scheduled intervals. + */ public class AnalyzerService implements Runnable { private final Analyzer analyzer; + /** + * Constructs an AnalyzerService with the specified analyzer. + * + * @param analyzer the analyzer to be used by the service + */ private AnalyzerService(Analyzer analyzer) { this.analyzer = analyzer; } + /** + * Creates and schedules an AnalyzerService. + * + * @param executorService the executor service to schedule the analyzer service + * @param analyzer the analyzer to be used by the service + */ public static void create(ScheduledExecutorService executorService, Analyzer analyzer) { var analyzerService = new AnalyzerService(analyzer); executorService.scheduleAtFixedRate(analyzerService, 10, 60, TimeUnit.MINUTES); } + /** + * Runs the analyzer cleanup process. + */ @Override public void run() { analyzer.cleanup(); diff --git a/src/main/java/de/chojo/repbot/service/GdprService.java b/src/main/java/de/chojo/repbot/service/GdprService.java index d54414619..4bf8c88c6 100644 --- a/src/main/java/de/chojo/repbot/service/GdprService.java +++ b/src/main/java/de/chojo/repbot/service/GdprService.java @@ -21,6 +21,9 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Service for handling GDPR-related tasks. + */ public class GdprService implements Runnable { private static final Logger log = getLogger(GdprService.class); private final ShardManager shardManager; @@ -28,6 +31,14 @@ public class GdprService implements Runnable { private final Guilds guilds; private final Gdpr gdpr; + /** + * Constructs a new GdprService instance. + * + * @param shardManager the ShardManager instance + * @param guilds the Guilds instance + * @param gdpr the Gdpr instance + * @param executorService the ExecutorService instance + */ private GdprService(ShardManager shardManager, Guilds guilds, Gdpr gdpr, ExecutorService executorService) { this.shardManager = shardManager; this.guilds = guilds; @@ -35,6 +46,15 @@ private GdprService(ShardManager shardManager, Guilds guilds, Gdpr gdpr, Executo this.executorService = executorService; } + /** + * Creates and schedules a new GdprService instance. + * + * @param shardManager the ShardManager instance + * @param guilds the Guilds instance + * @param gdpr the Gdpr instance + * @param scheduledExecutorService the ScheduledExecutorService instance + * @return the created GdprService instance + */ public static GdprService of(ShardManager shardManager, Guilds guilds, Gdpr gdpr, ScheduledExecutorService scheduledExecutorService) { var service = new GdprService(shardManager, guilds, gdpr, scheduledExecutorService); @@ -42,6 +62,9 @@ public static GdprService of(ShardManager shardManager, Guilds guilds, Gdpr gdpr return service; } + /** + * Runs the GDPR service tasks. + */ @Override public void run() { var reportRequests = gdpr.getReportRequests(shardManager); @@ -62,7 +85,12 @@ public void run() { cleanupGuilds(); } - + /** + * Cleans up user data for a specific guild. + * + * @param guild the Guild instance + * @return a CompletableFuture with the number of pruned users + */ public CompletableFuture cleanupGuildUsers(Guild guild) { return CompletableFuture.supplyAsync(() -> { log.info("Guild prune was started on {}", guild.getId()); @@ -83,11 +111,20 @@ public CompletableFuture cleanupGuildUsers(Guild guild) { }, executorService); } + /** + * Cleans up user data for a specific user in a guild. + * + * @param guild the Guild instance + * @param user the user ID + */ public void cleanupGuildUser(Guild guild, Long user) { log.info("User data of {} was pruned on guild {}.", user, guild.getIdLong()); CompletableFuture.runAsync(() -> RemovalTask.anonymExecute(guild.getIdLong(), user), executorService); } + /** + * Cleans up guilds by checking their status and updating their GDPR deletion queue. + */ private void cleanupGuilds() { for (var page : guilds.guilds(100)) { for (var guild : page) { diff --git a/src/main/java/de/chojo/repbot/service/MetricService.java b/src/main/java/de/chojo/repbot/service/MetricService.java index ece8c15a4..351081640 100644 --- a/src/main/java/de/chojo/repbot/service/MetricService.java +++ b/src/main/java/de/chojo/repbot/service/MetricService.java @@ -14,13 +14,28 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +/** + * Service for handling metric-related tasks. + */ public class MetricService implements Runnable { private final Metrics metrics; + /** + * Constructs a new MetricService with the specified metrics provider. + * + * @param metrics the metrics provider + */ public MetricService(Metrics metrics) { this.metrics = metrics; } + /** + * Creates and schedules a new MetricService. + * + * @param executorService the executor service to schedule the task + * @param metrics the metrics provider + * @return the created MetricService + */ public static MetricService create(ScheduledExecutorService executorService, Metrics metrics) { var now = ZonedDateTime.now(ZoneOffset.UTC); var base = now.toLocalDate().atStartOfDay().plus(1, ChronoUnit.DAYS).plus(1, ChronoUnit.HOURS) @@ -31,6 +46,9 @@ public static MetricService create(ScheduledExecutorService executorService, Met return service; } + /** + * Runs the metric saving tasks. + */ @Override public void run() { metrics.reputation().saveRepCounts(); diff --git a/src/main/java/de/chojo/repbot/service/PresenceService.java b/src/main/java/de/chojo/repbot/service/PresenceService.java index 265577493..9e5b13ff4 100644 --- a/src/main/java/de/chojo/repbot/service/PresenceService.java +++ b/src/main/java/de/chojo/repbot/service/PresenceService.java @@ -17,18 +17,36 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Service for managing the bot's presence. + */ public class PresenceService implements Runnable { private static final Logger log = getLogger(PresenceService.class); private final ShardManager shardManager; private final Configuration configuration; private final Statistic statistic; + /** + * Constructs a PresenceService with the specified shard manager, configuration, and statistic. + * + * @param shardManager the shard manager + * @param configuration the configuration + * @param statistic the statistic + */ public PresenceService(ShardManager shardManager, Configuration configuration, Statistic statistic) { this.shardManager = shardManager; this.configuration = configuration; this.statistic = statistic; } + /** + * Starts the presence service if it is active in the configuration. + * + * @param shardManager the shard manager + * @param configuration the configuration + * @param statistic the statistic + * @param executorService the scheduled executor service + */ public static void start(ShardManager shardManager, Configuration configuration, Statistic statistic, ScheduledExecutorService executorService) { var presenceService = new PresenceService(shardManager, configuration, statistic); if (configuration.presence().isActive()) { @@ -37,12 +55,18 @@ public static void start(ShardManager shardManager, Configuration configuration, } } + /** + * Runs the presence service, refreshing the presence if it is active. + */ @Override public void run() { if (!configuration.presence().isActive()) return; refresh(); } + /** + * Refreshes the bot's presence based on the current configuration and statistics. + */ private void refresh() { var replacements = statistic.getSystemStatistic().replacements(); var currentPresence = configuration.presence().randomStatus(); diff --git a/src/main/java/de/chojo/repbot/service/RepBotCachePolicy.java b/src/main/java/de/chojo/repbot/service/RepBotCachePolicy.java index b30a26a52..9536ba991 100644 --- a/src/main/java/de/chojo/repbot/service/RepBotCachePolicy.java +++ b/src/main/java/de/chojo/repbot/service/RepBotCachePolicy.java @@ -17,22 +17,44 @@ import java.util.HashSet; import java.util.Set; +/** + * Custom cache policy for managing member caching in the bot. + */ public class RepBotCachePolicy implements MemberCachePolicy, Runnable { + /** + * Duration for which members are cached, in minutes. + */ public static final int CACHE_DURATION = 30; private final HashMap seen = new HashMap<>(); private final Scan scan; - private final Roles roles; + /** + * Constructs a RepBotCachePolicy with the specified scan and roles handlers. + * + * @param scan the scan handler + * @param roles the roles handler + */ public RepBotCachePolicy(Scan scan, Roles roles) { this.scan = scan; this.roles = roles; } + /** + * Marks a member as seen at the current time. + * + * @param member the member to mark as seen + */ public void seen(Member member) { seen.put(member.getIdLong(), Instant.now()); } + /** + * Determines whether a member should be cached based on various conditions. + * + * @param member the member to check + * @return true if the member should be cached, false otherwise + */ @Override public boolean cacheMember(@NotNull Member member) { if (MemberCachePolicy.VOICE.cacheMember(member)) { @@ -68,11 +90,17 @@ public boolean cacheMember(@NotNull Member member) { return false; } + /** + * Runs the cache cleaning process. + */ @Override public void run() { clean(); } + /** + * Cleans the cache by removing members that have not been seen recently. + */ public synchronized void clean() { Set remove = new HashSet<>(); var oldest = oldest(); @@ -84,6 +112,11 @@ public synchronized void clean() { remove.forEach(seen::remove); } + /** + * Returns the oldest time that a member can be seen and still be cached. + * + * @return the oldest acceptable time + */ private Instant oldest() { return Instant.now().minus(CACHE_DURATION, ChronoUnit.MINUTES); } diff --git a/src/main/java/de/chojo/repbot/service/RoleAccessException.java b/src/main/java/de/chojo/repbot/service/RoleAccessException.java index ab8899520..315af7249 100644 --- a/src/main/java/de/chojo/repbot/service/RoleAccessException.java +++ b/src/main/java/de/chojo/repbot/service/RoleAccessException.java @@ -7,18 +7,31 @@ import net.dv8tion.jda.api.entities.Role; +/** + * Exception thrown when there is an issue accessing a role. + */ public class RoleAccessException extends RuntimeException { + /** + * The role that caused the exception. + */ private final Role role; /** * Constructs a new exception with {@code null} as its detail message. * The cause is not initialized, and may subsequently be initialized by a * call to {@link #initCause}. + * + * @param role the role that caused the exception */ public RoleAccessException(Role role) { this.role = role; } + /** + * Returns the role that caused the exception. + * + * @return the role + */ public Role role() { return role; } diff --git a/src/main/java/de/chojo/repbot/service/RoleAssigner.java b/src/main/java/de/chojo/repbot/service/RoleAssigner.java index f457a34cb..ea39e09f0 100644 --- a/src/main/java/de/chojo/repbot/service/RoleAssigner.java +++ b/src/main/java/de/chojo/repbot/service/RoleAssigner.java @@ -37,18 +37,27 @@ import static de.chojo.repbot.util.Guilds.prettyName; import static org.slf4j.LoggerFactory.getLogger; +/** + * Service for assigning roles based on reputation. + */ public class RoleAssigner { private static final Logger log = getLogger(RoleAssigner.class); private final Guilds guilds; private final ILocalizer localizer; + /** + * Constructs a new RoleAssigner. + * + * @param guilds the guilds provider + * @param localizer the localizer + */ public RoleAssigner(Guilds guilds, ILocalizer localizer) { this.guilds = guilds; this.localizer = localizer; } /** - * Updates the user roles. Will handle excpetions and send a message if the role could not be assigned. + * Updates the user roles. Will handle exceptions and send a message if the role could not be assigned. * * @param member member to update * @param channel channel to send the message to @@ -86,7 +95,7 @@ public Optional updateSilent(Member member) { * * @param member member to update * @return the new highest role of the member, if it changed. - * @throws RoleAccessException if the role cant be accessed + * @throws RoleAccessException if the role can't be accessed */ public Optional update(@Nullable Member member) throws RoleAccessException { if (member == null) return Optional.empty(); @@ -114,6 +123,14 @@ public Optional update(@Nullable Member member) throws RoleAcces return settings.ranks().currentRank(reputation); } + /** + * Removes roles from the member that are not in the provided set of roles. + * + * @param member the member + * @param roles the set of roles to retain + * @return true if any roles were removed, false otherwise + * @throws RoleAccessException if the role can't be accessed + */ private boolean cleanMemberRoles(Member member, Set roles) throws RoleAccessException { var guild = member.getGuild(); @@ -137,6 +154,13 @@ private boolean cleanMemberRoles(Member member, Set roles) throws RoleAcce return changed; } + /** + * Adds roles to the member that are in the provided set of roles. + * + * @param member the member + * @param roles the set of roles to add + * @return true if any roles were added, false otherwise + */ private boolean addMemberRoles(Member member, Set roles) { var guild = member.getGuild(); if (new HashSet<>(member.getRoles()).containsAll(roles)) return false; @@ -154,12 +178,27 @@ private boolean addMemberRoles(Member member, Set roles) { return changed; } + /** + * Asserts that the bot can interact with the specified role. + * + * @param role the role + * @param guild the guild + * @throws RoleAccessException if the role can't be accessed + */ private void assertInteract(Role role, Guild guild) throws RoleAccessException { if (!guild.getSelfMember().canInteract(role)) { throw new RoleAccessException(role); } } + /** + * Updates the roles of members in a batch. + * + * @param guild the guild + * @param context the event context + * @param message the message to update with progress + * @return a CompletableFuture with the batch update result + */ public CompletableFuture updateBatch(Guild guild, EventContext context, Message message) { return CompletableFuture.supplyAsync(() -> { log.info("Started batch update for guild {}", prettyName(guild)); @@ -185,6 +224,12 @@ public CompletableFuture updateBatch(Guild guild, EventContex }); } + /** + * Result of a batch update. + * + * @param checked the number of members checked + * @param updated the number of members updated + */ public record BatchUpdateResult(int checked, int updated) { } } diff --git a/src/main/java/de/chojo/repbot/service/RoleUpdater.java b/src/main/java/de/chojo/repbot/service/RoleUpdater.java index 2d355a49d..e73cc2591 100644 --- a/src/main/java/de/chojo/repbot/service/RoleUpdater.java +++ b/src/main/java/de/chojo/repbot/service/RoleUpdater.java @@ -26,12 +26,24 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +/** + * Service for updating roles based on reputation. + */ public class RoleUpdater extends ListenerAdapter { private final Guilds guilds; private final Map> checked = new HashMap<>(); private final RoleAssigner roleAssigner; private final ShardManager shardManager; + /** + * Creates a new RoleUpdater and schedules periodic tasks. + * + * @param guilds the guilds provider + * @param roleAssigner the role assigner + * @param shardManager the shard manager + * @param executorService the executor service for scheduling tasks + * @return the created RoleUpdater + */ public static RoleUpdater create(Guilds guilds, RoleAssigner roleAssigner, ShardManager shardManager, ScheduledExecutorService executorService) { var roleUpdater = new RoleUpdater(guilds, roleAssigner, shardManager); executorService.scheduleAtFixedRate(roleUpdater.checked::clear, 30, 30, TimeUnit.MINUTES); @@ -43,12 +55,22 @@ public static RoleUpdater create(Guilds guilds, RoleAssigner roleAssigner, Shard return roleUpdater; } + /** + * Constructs a new RoleUpdater. + * + * @param guilds the guilds provider + * @param roleAssigner the role assigner + * @param shardManager the shard manager + */ public RoleUpdater(Guilds guilds, RoleAssigner roleAssigner, ShardManager shardManager) { this.guilds = guilds; this.roleAssigner = roleAssigner; this.shardManager = shardManager; } + /** + * Periodically updates roles based on the current date. + */ private void updateTimed() { if (ZonedDateTime.now().getDayOfMonth() == 1) { for (var guild : guilds.byReputationMode(ReputationMode.MONTH)) { @@ -63,6 +85,11 @@ private void updateTimed() { } } + /** + * Updates roles for the given guild. + * + * @param guild the guild to update roles for + */ private void updateRoles(RepGuild guild) { guild.load(shardManager); if (guild.isById()) return; @@ -79,6 +106,11 @@ private void updateRoles(RepGuild guild) { } } + /** + * Handles the MessageReceived event to update roles if necessary. + * + * @param event the message received event + */ @Override public void onMessageReceived(@NotNull MessageReceivedEvent event) { if (!event.isFromGuild()) return; @@ -88,10 +120,22 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { guildSet(event.getGuild()).add(event.getMember().getIdLong()); } + /** + * Checks if the member has already been checked. + * + * @param member the member to check + * @return true if the member has been checked, false otherwise + */ public boolean isChecked(Member member) { return guildSet(member.getGuild()).contains(member.getIdLong()); } + /** + * Retrieves the set of checked members for the given guild. + * + * @param guild the guild + * @return the set of checked members + */ public Set guildSet(Guild guild) { return checked.computeIfAbsent(guild.getIdLong(), k -> new HashSet<>()); } diff --git a/src/main/java/de/chojo/repbot/service/SelfCleanupService.java b/src/main/java/de/chojo/repbot/service/SelfCleanupService.java index 58e45d06a..304090ad3 100644 --- a/src/main/java/de/chojo/repbot/service/SelfCleanupService.java +++ b/src/main/java/de/chojo/repbot/service/SelfCleanupService.java @@ -29,6 +29,9 @@ import static de.chojo.repbot.util.Guilds.prettyName; import static org.slf4j.LoggerFactory.getLogger; +/** + * Service class for handling self-cleanup operations. + */ public class SelfCleanupService implements Runnable { private static final Logger log = getLogger(SelfCleanupService.class); private final ShardManager shardManager; @@ -37,6 +40,15 @@ public class SelfCleanupService implements Runnable { private final Configuration configuration; private final Cleanup cleanup; + /** + * Constructs a new SelfCleanupService. + * + * @param shardManager the shard manager + * @param localizer the localizer + * @param guilds the guilds provider + * @param cleanup the cleanup access object + * @param configuration the configuration object + */ private SelfCleanupService(ShardManager shardManager, ILocalizer localizer, Guilds guilds, Cleanup cleanup, Configuration configuration) { this.shardManager = shardManager; this.localizer = localizer; @@ -45,12 +57,24 @@ private SelfCleanupService(ShardManager shardManager, ILocalizer localizer, Guil this.configuration = configuration; } + /** + * Creates and schedules a new SelfCleanupService. + * + * @param shardManager the shard manager + * @param localizer the localizer + * @param guilds the guilds provider + * @param cleanup the cleanup access object + * @param configuration the configuration object + * @param service the scheduled executor service + */ public static void create(ShardManager shardManager, ILocalizer localizer, Guilds guilds, Cleanup cleanup, Configuration configuration, ScheduledExecutorService service) { var selfCleanupService = new SelfCleanupService(shardManager, localizer, guilds, cleanup, configuration); service.scheduleAtFixedRate(selfCleanupService, 1, 60, TimeUnit.MINUTES); } - + /** + * Runs the self-cleanup process. + */ @Override public void run() { if (!configuration.selfCleanup().isActive()) return; @@ -77,7 +101,6 @@ public void run() { continue; } - var channels = repGuild.settings().thanking().channels(); if (channels.isWhitelist()) { // Check if channel or categories are registered. @@ -117,10 +140,15 @@ public void run() { } } + /** + * Prompts the guild for cleanup. + * + * @param guild the guild to prompt + */ private void promptCleanup(Guild guild) { var repGuild = guilds.guild(guild); - // Check if a prompt was already send + // Check if a prompt was already sent if (repGuild.cleanup().getCleanupPromptTime().isPresent()) return; repGuild.cleanup().selfCleanupPrompt(); @@ -137,10 +165,15 @@ private void promptCleanup(Guild guild) { log.info(LogNotify.STATUS, "Prompted guild self cleanup."); } + /** + * Notifies the guild for cleanup and leaves the guild. + * + * @param guild the guild to notify and leave + */ private void notifyCleanup(Guild guild) { var clean = guilds.guild(guild).cleanup(); if (clean.getCleanupPromptTime().get().isAfter(configuration.selfCleanup().getLeaveDaysOffset())) { - log.debug("Prompt was send {}/{} days ago on {}", + log.debug("Prompt was sent {}/{} days ago on {}", Math.abs(Duration.between(clean.getCleanupPromptTime().get(), LocalDateTime.now().atZone(ZoneOffset.UTC)).toDays()), configuration.selfCleanup().leaveDays(), @@ -160,6 +193,12 @@ private void notifyCleanup(Guild guild) { clean.cleanupDone(); } + /** + * Notifies the guild with the given embed message. + * + * @param guild the guild to notify + * @param embed the embed message to send + */ private void notifyGuild(Guild guild, MessageEmbed embed) { var selfMember = guild.getSelfMember(); guild.retrieveMemberById(guild.getOwnerIdLong()) @@ -176,6 +215,9 @@ private void notifyGuild(Guild guild, MessageEmbed embed) { } } + /** + * Enum representing inactivity markers. + */ private enum InactivityMarker { NO_REPUTATION, NO_CHANNEL, diff --git a/src/main/java/de/chojo/repbot/service/reputation/ReputationService.java b/src/main/java/de/chojo/repbot/service/reputation/ReputationService.java index f05047c74..de7c9eb19 100644 --- a/src/main/java/de/chojo/repbot/service/reputation/ReputationService.java +++ b/src/main/java/de/chojo/repbot/service/reputation/ReputationService.java @@ -37,6 +37,9 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Service for handling reputation submissions and related operations. + */ public class ReputationService { private static final Logger log = getLogger(ReputationService.class); private final Guilds guilds; @@ -46,6 +49,15 @@ public class ReputationService { private final ILocalizer localizer; private Instant lastEasterEggSent = Instant.EPOCH; + /** + * Constructs a new ReputationService. + * + * @param guilds the guilds provider + * @param contextResolver the context resolver + * @param assigner the role assigner + * @param magicImage the magic image configuration + * @param localizer the localizer + */ public ReputationService(Guilds guilds, ContextResolver contextResolver, RoleAssigner assigner, MagicImage magicImage, ILocalizer localizer) { this.guilds = guilds; this.assigner = assigner; @@ -55,16 +67,16 @@ public ReputationService(Guilds guilds, ContextResolver contextResolver, RoleAss } /** - * Submit a reputation. + * Submits a reputation. *

* This reputation will be checked by several factors based on the {@link de.chojo.repbot.dao.access.guild.settings.Settings}. * - * @param guild guild where the vote was given - * @param donor donor of the reputation - * @param receiver receiver of the reputation - * @param message triggered message - * @param refMessage reference message if present - * @param type type of reputation source + * @param guild the guild where the vote was given + * @param donor the donor of the reputation + * @param receiver the receiver of the reputation + * @param message the triggered message + * @param refMessage the reference message if present + * @param type the type of reputation source * @return true if the reputation was counted and is valid */ public boolean submitReputation(Guild guild, Member donor, Member receiver, Message message, @Nullable Message refMessage, ThankType type) { @@ -111,6 +123,15 @@ public boolean submitReputation(Guild guild, Member donor, Member receiver, Mess return log(guild, donor, receiver, message, refMessage, type, settings); } + /** + * Retrieves the message context based on the donor, message, type, and settings. + * + * @param donor the donor of the reputation + * @param message the triggered message + * @param type the type of reputation source + * @param settings the settings + * @return the message context + */ private MessageContext getContext(Member donor, Message message, ThankType type, Settings settings) { MessageContext context; if (type == ThankType.REACTION) { @@ -122,6 +143,17 @@ private MessageContext getContext(Member donor, Message message, ThankType type, return context; } + /** + * Asserts abuse protection rules. + * + * @param guild the guild + * @param donor the donor of the reputation + * @param receiver the receiver of the reputation + * @param message the triggered message + * @param refMessage the reference message if present + * @param context the message context + * @return true if abuse protection rules are violated, false otherwise + */ private boolean assertAbuseProtection(Guild guild, Member donor, Member receiver, Message message, @Nullable Message refMessage, MessageContext context) { var repGuild = guilds.guild(guild); var analyzer = repGuild.reputation().analyzer(); @@ -191,6 +223,14 @@ private boolean assertAbuseProtection(Guild guild, Member donor, Member receiver return false; } + /** + * Checks if the vote is a self-vote. + * + * @param donor the donor of the reputation + * @param receiver the receiver of the reputation + * @param message the triggered message + * @return true if it is a self-vote, false otherwise + */ private boolean isSelfVote(Member donor, Member receiver, Message message) { // block self vote if (Verifier.equalSnowflake(receiver, donor)) { @@ -215,6 +255,18 @@ private boolean isSelfVote(Member donor, Member receiver, Message message) { return false; } + /** + * Logs the reputation submission. + * + * @param guild the guild + * @param donor the donor of the reputation + * @param receiver the receiver of the reputation + * @param message the triggered message + * @param refMessage the reference message if present + * @param type the type of reputation source + * @param settings the settings + * @return true if the reputation was logged successfully, false otherwise + */ private boolean log(Guild guild, Member donor, Member receiver, Message message, @Nullable Message refMessage, ThankType type, Settings settings) { var repGuild = guilds.guild(guild); // try to log reputation @@ -248,6 +300,13 @@ private boolean log(Guild guild, Member donor, Member receiver, Message message, return true; } + /** + * Checks if the given reputation type is disabled in the settings. + * + * @param type the type of reputation source + * @param reputation the reputation settings + * @return true if the type is disabled, false otherwise + */ private boolean isTypeDisabled(ThankType type, Reputation reputation) { // force settings switch (type) { @@ -274,6 +333,16 @@ private boolean isTypeDisabled(ThankType type, Reputation reputation) { return false; } + /** + * Checks if the donor can vote for the receiver. + * + * @param message the triggered message + * @param donor the donor of the reputation + * @param receiver the receiver of the reputation + * @param guild the guild + * @param settings the settings + * @return true if the donor can vote, false otherwise + */ public boolean canVote(Message message, Member donor, Member receiver, Guild guild, Settings settings) { var repGuild = settings.repGuild(); var analyzer = repGuild.reputation().analyzer(); diff --git a/src/main/java/de/chojo/repbot/service/reputation/SubmitResult.java b/src/main/java/de/chojo/repbot/service/reputation/SubmitResult.java index 4ea26cdee..810c487c3 100644 --- a/src/main/java/de/chojo/repbot/service/reputation/SubmitResult.java +++ b/src/main/java/de/chojo/repbot/service/reputation/SubmitResult.java @@ -11,12 +11,32 @@ import java.util.List; +/** + * Record representing the result of a submission. + * + * @param type the type of the submission result + * @param replacements the list of replacements associated with the submission result + */ public record SubmitResult(SubmitResultType type, List replacements) { + /** + * Creates a new SubmitResult instance with the given type and replacements. + * + * @param type the type of the submission result + * @param replacements the array of replacements associated with the submission result + * @return a new SubmitResult instance + */ public static SubmitResult of(SubmitResultType type, Replacement... replacements){ return of(type, List.of(replacements)); } + /** + * Creates a new SubmitResult instance with the given type and replacements. + * + * @param type the type of the submission result + * @param replacements the list of replacements associated with the submission result + * @return a new SubmitResult instance + */ @JsonCreator public static SubmitResult of(@JsonProperty("type") SubmitResultType type, @JsonProperty("replacements") List replacements){ return new SubmitResult(type, replacements); diff --git a/src/main/java/de/chojo/repbot/service/reputation/SubmitResultType.java b/src/main/java/de/chojo/repbot/service/reputation/SubmitResultType.java index ec9a1d706..39a9d9185 100644 --- a/src/main/java/de/chojo/repbot/service/reputation/SubmitResultType.java +++ b/src/main/java/de/chojo/repbot/service/reputation/SubmitResultType.java @@ -5,32 +5,116 @@ */ package de.chojo.repbot.service.reputation; +/** + * Enum representing the different types of submission results. + */ public enum SubmitResultType { + /** + * No donor role found. + */ NO_DONOR_ROLE("submitresult.nodonorrole"), + + /** + * Channel is inactive. + */ CHANNEL_INACTIVE("submitresult.channelinactive"), + + /** + * No targets found. + */ NO_TARGETS("submitresult.notargets"), + + /** + * No recent members found. + */ NO_RECENT_MEMBERS("submitresult.norecentmembers"), + + /** + * Cooldown is active. + */ COOLDOWN_ACTIVE("submitresult.cooldownactive"), + + /** + * Embed send operation. + */ EMBED_SEND("submitresult.embedsend"), + + /** + * Donor limit reached. + */ DONOR_LIMIT("submitresult.donorlimit"), + + /** + * No receiver role found. + */ NO_RECEIVER_ROLE("submitresult.noreceiverrole"), + + /** + * Thank type is disabled. + */ THANK_TYPE_DISABLED("submitresult.thanktypedisabled"), + + /** + * Self vote detected. + */ SELF_VOTE("submitresult.selfvote"), + + /** + * Target not in context. + */ TARGET_NOT_IN_CONTEXT("submitresult.targetnotincontext"), + + /** + * Donor not in context. + */ DONOR_NOT_IN_CONTEXT("submitresult.donornotincontext"), + + /** + * Outdated reference message. + */ OUTDATED_REFERENCE_MESSAGE("submitresult.outdatedreferencemessage"), + + /** + * Outdated message. + */ OUTDATED_MESSAGE("submitresult.outdatedmessage"), + + /** + * Receiver limit reached. + */ RECEIVER_LIMIT("submitresult.receiverlimit"), + + /** + * Already present. + */ ALREADY_PRESENT("submitresult.alreadypresent"), + + /** + * Submitting operation. + */ SUBMITTING("submitresult.submitting"), + + /** + * All cooldowns are active. + */ ALL_COOLDOWN("submitresult.allcooldown"); private final String localeKey; + /** + * Constructs a new SubmitResultType with the given locale key. + * + * @param localeKey the locale key associated with the submission result type + */ SubmitResultType(String localeKey) { this.localeKey = localeKey; } + /** + * Retrieves the locale key associated with the submission result type. + * + * @return the locale key + */ public String localeKey() { return localeKey; } diff --git a/src/main/java/de/chojo/repbot/statistic/EmbedDisplay.java b/src/main/java/de/chojo/repbot/statistic/EmbedDisplay.java index e266cb28a..5a98c0265 100644 --- a/src/main/java/de/chojo/repbot/statistic/EmbedDisplay.java +++ b/src/main/java/de/chojo/repbot/statistic/EmbedDisplay.java @@ -7,7 +7,15 @@ import net.dv8tion.jda.api.EmbedBuilder; +/** + * Functional interface for appending content to an EmbedBuilder. + */ @FunctionalInterface public interface EmbedDisplay { + /** + * Appends content to the provided EmbedBuilder. + * + * @param embedBuilder the EmbedBuilder to append content to + */ void appendTo(EmbedBuilder embedBuilder); } diff --git a/src/main/java/de/chojo/repbot/statistic/ReplacementProvider.java b/src/main/java/de/chojo/repbot/statistic/ReplacementProvider.java index 21c95a43f..754f0f937 100644 --- a/src/main/java/de/chojo/repbot/statistic/ReplacementProvider.java +++ b/src/main/java/de/chojo/repbot/statistic/ReplacementProvider.java @@ -9,7 +9,15 @@ import java.util.List; +/** + * Functional interface for providing a list of replacements. + */ @FunctionalInterface public interface ReplacementProvider { + /** + * Returns a list of replacements. + * + * @return a list of {@link Replacement} objects + */ List replacements(); } diff --git a/src/main/java/de/chojo/repbot/statistic/Statistic.java b/src/main/java/de/chojo/repbot/statistic/Statistic.java index c7ce89221..60b7aa64b 100644 --- a/src/main/java/de/chojo/repbot/statistic/Statistic.java +++ b/src/main/java/de/chojo/repbot/statistic/Statistic.java @@ -20,23 +20,46 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Class responsible for gathering and refreshing statistics for the bot. + */ public class Statistic { private static final Logger log = getLogger(Statistic.class); private final ShardManager shardManager; private final Metrics metrics; + /** + * Constructs a new Statistic instance. + * + * @param shardManager the shard manager + * @param metrics the metrics provider + */ private Statistic(ShardManager shardManager, Metrics metrics) { this.shardManager = shardManager; this.metrics = metrics; getSystemStatistic(); } + /** + * Creates a new Statistic instance and schedules periodic refresh of statistics. + * + * @param shardManager the shard manager + * @param metrics the metrics provider + * @param service the scheduled executor service + * @return the created Statistic instance + */ public static Statistic of(ShardManager shardManager, Metrics metrics, ScheduledExecutorService service) { var statistic = new Statistic(shardManager, metrics); service.scheduleAtFixedRate(statistic::refreshStatistics, 1, 30, TimeUnit.MINUTES); return statistic; } + /** + * Gathers statistics for a specific shard. + * + * @param jda the JDA instance + * @return the gathered ShardStatistic + */ private ShardStatistic getShardStatistic(JDA jda) { var shardId = jda.getShardInfo().getShardId(); var analyzedMessages = metrics.messages().hour(1, 1).get(0).count(); @@ -48,6 +71,11 @@ private ShardStatistic getShardStatistic(JDA jda) { jda.getGuildCache().size()); } + /** + * Gathers system-wide statistics. + * + * @return the gathered SystemStatistics + */ public SystemStatistics getSystemStatistic() { var shardStatistics = shardManager.getShardCache() .stream() @@ -59,6 +87,9 @@ public SystemStatistics getSystemStatistic() { shardStatistics); } + /** + * Refreshes the statistics in the metrics provider. + */ private void refreshStatistics() { metrics.statistic().refreshStatistics(); } diff --git a/src/main/java/de/chojo/repbot/statistic/display/GlobalInfoStatisticDisplay.java b/src/main/java/de/chojo/repbot/statistic/display/GlobalInfoStatisticDisplay.java index 89273d95b..2d3d44ac9 100644 --- a/src/main/java/de/chojo/repbot/statistic/display/GlobalInfoStatisticDisplay.java +++ b/src/main/java/de/chojo/repbot/statistic/display/GlobalInfoStatisticDisplay.java @@ -10,10 +10,20 @@ import de.chojo.repbot.statistic.element.GlobalShardStatistic; import net.dv8tion.jda.api.EmbedBuilder; +/** + * Represents a display for global information statistics. + * + * @param globalShardStatistic the global shard statistics + * @param dataStatistic the data statistics + */ public record GlobalInfoStatisticDisplay(GlobalShardStatistic globalShardStatistic, DataStatistic dataStatistic) implements EmbedDisplay { - + /** + * Appends the global information statistics to the provided embed builder. + * + * @param embedBuilder the embed builder to append the statistics to + */ @Override public void appendTo(EmbedBuilder embedBuilder) { embedBuilder.addField("Global Info", diff --git a/src/main/java/de/chojo/repbot/statistic/display/SystemInfoStatisticDisplay.java b/src/main/java/de/chojo/repbot/statistic/display/SystemInfoStatisticDisplay.java index 6c143f88e..770b85011 100644 --- a/src/main/java/de/chojo/repbot/statistic/display/SystemInfoStatisticDisplay.java +++ b/src/main/java/de/chojo/repbot/statistic/display/SystemInfoStatisticDisplay.java @@ -10,9 +10,20 @@ import de.chojo.repbot.statistic.element.ShardCountStatistic; import net.dv8tion.jda.api.EmbedBuilder; +/** + * Class representing the system information statistic display. + * + * @param shardCountStatistic the shard count statistic + * @param dataStatistic the data statistic + */ public record SystemInfoStatisticDisplay(ShardCountStatistic shardCountStatistic, DataStatistic dataStatistic) implements EmbedDisplay { + /** + * Appends the system information statistics to the given EmbedBuilder. + * + * @param embedBuilder the EmbedBuilder to append to + */ @Override public void appendTo(EmbedBuilder embedBuilder) { embedBuilder.setTitle("System Info") diff --git a/src/main/java/de/chojo/repbot/statistic/element/DataStatistic.java b/src/main/java/de/chojo/repbot/statistic/element/DataStatistic.java index 9f5ee482d..0135864c1 100644 --- a/src/main/java/de/chojo/repbot/statistic/element/DataStatistic.java +++ b/src/main/java/de/chojo/repbot/statistic/element/DataStatistic.java @@ -10,6 +10,9 @@ import java.util.List; +/** + * Class representing data statistics for the application. + */ public class DataStatistic implements ReplacementProvider { private final int guilds; private final int activeGuilds; @@ -20,10 +23,25 @@ public class DataStatistic implements ReplacementProvider { private final int weeklyRep; private final int weeklyAvgRep; + /** + * Constructs a DataStatistic instance with default values. + */ public DataStatistic() { this(0, 0, 0, 0, 0, 0, 0, 0); } + /** + * Constructs a DataStatistic instance with the specified values. + * + * @param guilds the number of guilds + * @param activeGuilds the number of active guilds + * @param activeChannel the number of active channels + * @param channel the number of channels + * @param totalRep the total reputation + * @param todayRep the reputation for today + * @param weeklyRep the weekly reputation + * @param weeklyAvgRep the weekly average reputation + */ public DataStatistic(int guilds, int activeGuilds, int activeChannel, int channel, int totalRep, int todayRep, int weeklyRep, int weeklyAvgRep) { this.guilds = guilds; this.activeGuilds = activeGuilds; @@ -35,38 +53,83 @@ public DataStatistic(int guilds, int activeGuilds, int activeChannel, int channe this.weeklyAvgRep = weeklyAvgRep; } + /** + * Returns the number of guilds. + * + * @return the number of guilds + */ public int guilds() { return guilds; } + /** + * Returns the number of channels. + * + * @return the number of channels + */ public int channel() { return channel; } + /** + * Returns the total reputation. + * + * @return the total reputation + */ public int totalRep() { return totalRep; } + /** + * Returns the reputation for today. + * + * @return the reputation for today + */ public int today() { return todayRep; } + /** + * Returns the weekly reputation. + * + * @return the weekly reputation + */ public int weeklyRep() { return weeklyRep; } + /** + * Returns the weekly average reputation. + * + * @return the weekly average reputation + */ public int weeklyAvgRep() { return weeklyAvgRep; } + /** + * Returns the number of active guilds. + * + * @return the number of active guilds + */ public int activeGuilds() { return activeGuilds; } + /** + * Returns the number of active channels. + * + * @return the number of active channels + */ public int activeChannel() { return activeChannel; } + /** + * Returns a list of replacements for localization. + * + * @return a list of {@link Replacement} objects + */ @Override public List replacements() { return List.of(Replacement.create("guild_count", guilds), Replacement.create("channel_count", channel), diff --git a/src/main/java/de/chojo/repbot/statistic/element/GlobalShardStatistic.java b/src/main/java/de/chojo/repbot/statistic/element/GlobalShardStatistic.java index 225e279db..8c3cfa66e 100644 --- a/src/main/java/de/chojo/repbot/statistic/element/GlobalShardStatistic.java +++ b/src/main/java/de/chojo/repbot/statistic/element/GlobalShardStatistic.java @@ -11,19 +11,36 @@ import java.util.Collections; import java.util.List; +/** + * Class representing global shard statistics. + */ public class GlobalShardStatistic implements ReplacementProvider { private final long analyzedMessages; + /** + * Constructs a new GlobalShardStatistic instance. + * + * @param shardStatistics a list of ShardStatistic instances + */ public GlobalShardStatistic(List shardStatistics) { analyzedMessages = shardStatistics.stream() .map(ShardStatistic::analyzedMessages).reduce(0L, Long::sum); } + /** + * Retrieves the total number of analyzed messages. + * + * @return the total number of analyzed messages + */ public long analyzedMessages() { return analyzedMessages; } - + /** + * Provides a list of replacements for localization. + * + * @return a list of Replacement instances + */ @Override public List replacements() { return Collections.singletonList(Replacement.create("analyzed_messages", analyzedMessages)); diff --git a/src/main/java/de/chojo/repbot/statistic/element/ProcessStatistics.java b/src/main/java/de/chojo/repbot/statistic/element/ProcessStatistics.java index 670631b53..8ced92f4a 100644 --- a/src/main/java/de/chojo/repbot/statistic/element/ProcessStatistics.java +++ b/src/main/java/de/chojo/repbot/statistic/element/ProcessStatistics.java @@ -15,12 +15,26 @@ import java.time.temporal.ChronoUnit; import java.util.List; +/** + * Represents the statistics of the current process, including memory usage and thread count. + * + * @param total the total memory available to the process + * @param used the memory currently used by the process + * @param free the free memory available to the process + * @param max the maximum memory available to the process + * @param threads the number of active threads in the process + */ public record ProcessStatistics(long total, long used, long free, long max, long threads) implements ReplacementProvider, EmbedDisplay { private static final int MB = 1024 * 1024; private static final Instant START = Instant.now(); + /** + * Creates a new instance of ProcessStatistics with the current process information. + * + * @return a new ProcessStatistics instance + */ public static ProcessStatistics create() { var instance = Runtime.getRuntime(); var total = instance.totalMemory() / MB; @@ -31,10 +45,20 @@ public static ProcessStatistics create() { return new ProcessStatistics(total, free, used, max, Thread.activeCount()); } + /** + * Gets the uptime of the process in milliseconds. + * + * @return the uptime of the process in milliseconds + */ public long uptime() { return START.until(Instant.now(), ChronoUnit.MILLIS); } + /** + * Provides a list of replacements for localization. + * + * @return a list of replacements + */ @Override public List replacements() { return List.of(Replacement.create("total_mem", total), Replacement.create("used_mem", used), @@ -42,6 +66,11 @@ public List replacements() { Replacement.create("threads", threads)); } + /** + * Appends the process statistics to the provided EmbedBuilder. + * + * @param embedBuilder the EmbedBuilder to append the statistics to + */ @Override public void appendTo(EmbedBuilder embedBuilder) { embedBuilder.addField("Process Info", diff --git a/src/main/java/de/chojo/repbot/statistic/element/ShardCountStatistic.java b/src/main/java/de/chojo/repbot/statistic/element/ShardCountStatistic.java index 8a22aa2e4..314174373 100644 --- a/src/main/java/de/chojo/repbot/statistic/element/ShardCountStatistic.java +++ b/src/main/java/de/chojo/repbot/statistic/element/ShardCountStatistic.java @@ -13,17 +13,37 @@ import java.util.Collections; import java.util.List; +/** + * Represents the statistics of shard counts. + * + * @param shardStatistics the list of shard statistics + */ public record ShardCountStatistic(List shardStatistics) implements ReplacementProvider, EmbedDisplay { + /** + * Returns the count of shards. + * + * @return the number of shards + */ public int shardCount() { return shardStatistics.size(); } + /** + * Provides a list of replacements for localization. + * + * @return a list of replacements + */ @Override public List replacements() { return Collections.singletonList(Replacement.create("shard_count", shardCount())); } + /** + * Appends shard statistics to the given embed builder. + * + * @param embedBuilder the embed builder to append to + */ @Override public void appendTo(EmbedBuilder embedBuilder) { for (var shard : shardStatistics) { diff --git a/src/main/java/de/chojo/repbot/statistic/element/ShardStatistic.java b/src/main/java/de/chojo/repbot/statistic/element/ShardStatistic.java index b5f7e17de..24877fa5d 100644 --- a/src/main/java/de/chojo/repbot/statistic/element/ShardStatistic.java +++ b/src/main/java/de/chojo/repbot/statistic/element/ShardStatistic.java @@ -11,9 +11,22 @@ import java.util.List; +/** + * Represents the statistics of a specific shard. + * + * @param shard the shard ID + * @param status the status of the shard + * @param analyzedMessages the number of analyzed messages + * @param guilds the number of guilds + */ public record ShardStatistic(int shard, JDA.Status status, long analyzedMessages, long guilds) implements ReplacementProvider { + /** + * Provides a list of replacements for localization. + * + * @return a list of replacements + */ @Override public List replacements() { return List.of(Replacement.create("analyzed_messages_shard", analyzedMessages), Replacement.create("shard_status", status.name()), diff --git a/src/main/java/de/chojo/repbot/statistic/element/SystemStatistics.java b/src/main/java/de/chojo/repbot/statistic/element/SystemStatistics.java index c1bc874de..74e46f25a 100644 --- a/src/main/java/de/chojo/repbot/statistic/element/SystemStatistics.java +++ b/src/main/java/de/chojo/repbot/statistic/element/SystemStatistics.java @@ -15,6 +15,9 @@ import java.util.ArrayList; import java.util.List; +/** + * Class representing system statistics, including process statistics, data statistics, and shard statistics. + */ public class SystemStatistics implements ReplacementProvider, EmbedDisplay { private final ProcessStatistics processStatistics; @@ -24,6 +27,13 @@ public class SystemStatistics implements ReplacementProvider, EmbedDisplay { private final GlobalInfoStatisticDisplay globalInfoStatisticDisplay; private final SystemInfoStatisticDisplay systemInfoStatisticDisplay; + /** + * Constructs a new SystemStatistics instance. + * + * @param processStatistics the process statistics + * @param dataStatistic the data statistics + * @param shardStatistics the list of shard statistics + */ public SystemStatistics(ProcessStatistics processStatistics, DataStatistic dataStatistic, List shardStatistics) { this.processStatistics = processStatistics; @@ -37,10 +47,20 @@ public SystemStatistics(ProcessStatistics processStatistics, DataStatistic dataS } + /** + * Retrieves the process statistics. + * + * @return the process statistics + */ public ProcessStatistics processStatistics() { return processStatistics; } + /** + * Appends the system statistics to the given EmbedBuilder. + * + * @param embedBuilder the EmbedBuilder to append to + */ @Override public void appendTo(EmbedBuilder embedBuilder) { systemInfoStatisticDisplay.appendTo(embedBuilder); @@ -49,18 +69,38 @@ public void appendTo(EmbedBuilder embedBuilder) { shardCountStatistic.appendTo(embedBuilder); } + /** + * Retrieves the aggregated shard statistics. + * + * @return the aggregated shard statistics + */ public GlobalShardStatistic aggregatedShards() { return aggregatedShards; } + /** + * Retrieves the data statistics. + * + * @return the data statistics + */ public DataStatistic dataStatistic() { return dataStatistic; } + /** + * Retrieves the shard count. + * + * @return the shard count + */ public int shardCount() { return shardCountStatistic.shardCount(); } + /** + * Retrieves the list of replacements for the system statistics. + * + * @return the list of replacements + */ @Override public List replacements() { List replacements = new ArrayList<>(); diff --git a/src/main/java/de/chojo/repbot/util/Colors.java b/src/main/java/de/chojo/repbot/util/Colors.java index 46b55d7e3..5a0edcb6b 100644 --- a/src/main/java/de/chojo/repbot/util/Colors.java +++ b/src/main/java/de/chojo/repbot/util/Colors.java @@ -20,21 +20,69 @@ private Colors() { */ @SuppressWarnings("unused") public static final class Pastel { + /** + * Light red pastel color. + */ public static final Color LIGHT_RED = new Color(235, 145, 145); + /** + * Red pastel color. + */ public static final Color RED = new Color(245, 93, 93); + /** + * Dark red pastel color. + */ public static final Color DARK_RED = new Color(168, 69, 69); + /** + * Orange pastel color. + */ public static final Color ORANGE = new Color(237, 156, 85); + /** + * Yellow pastel color. + */ public static final Color YELLOW = new Color(237, 221, 104); + /** + * Light green pastel color. + */ public static final Color LIGHT_GREEN = new Color(188, 242, 141); + /** + * Green pastel color. + */ public static final Color GREEN = new Color(137, 237, 123); + /** + * Dark green pastel color. + */ public static final Color DARK_GREEN = new Color(83, 158, 73); + /** + * Aqua pastel color. + */ public static final Color AQUA = new Color(183, 247, 247); + /** + * Light blue pastel color. + */ public static final Color LIGHT_BLUE = new Color(132, 204, 240); + /** + * Blue pastel color. + */ public static final Color BLUE = new Color(132, 161, 240); + /** + * Dark blue pastel color. + */ public static final Color DARK_BLUE = new Color(85, 106, 163); + /** + * Purple pastel color. + */ public static final Color PURPLE = new Color(189, 110, 204); + /** + * Dark pink pastel color. + */ public static final Color DARK_PINK = new Color(179, 57, 130); + /** + * Pink pastel color. + */ public static final Color PINK = new Color(201, 103, 177); + /** + * Light pink pastel color. + */ public static final Color LIGHT_PINK = new Color(209, 138, 192); private Pastel() { @@ -47,21 +95,69 @@ private Pastel() { */ @SuppressWarnings("unused") public static final class Strong { + /** + * Light red strong color. + */ public static final Color LIGHT_RED = new Color(255, 97, 97); + /** + * Red strong color. + */ public static final Color RED = new Color(255, 0, 0); + /** + * Dark red strong color. + */ public static final Color DARK_RED = new Color(176, 0, 0); + /** + * Orange strong color. + */ public static final Color ORANGE = new Color(255, 132, 0); + /** + * Yellow strong color. + */ public static final Color YELLOW = new Color(255, 255, 0); + /** + * Light green strong color. + */ public static final Color LIGHT_GREEN = new Color(74, 255, 95); + /** + * Green strong color. + */ public static final Color GREEN = new Color(0, 255, 30); + /** + * Dark green strong color. + */ public static final Color DARK_GREEN = new Color(0, 181, 21); + /** + * Aqua strong color. + */ public static final Color AQUA = new Color(0, 255, 255); + /** + * Light blue strong color. + */ public static final Color LIGHT_BLUE = new Color(77, 184, 255); + /** + * Blue strong color. + */ public static final Color BLUE = new Color(0, 0, 255); + /** + * Dark blue strong color. + */ public static final Color DARK_BLUE = new Color(0, 0, 191); + /** + * Purple strong color. + */ public static final Color PURPLE = new Color(187, 0, 255); + /** + * Dark pink strong color. + */ public static final Color DARK_PINK = new Color(219, 0, 102); + /** + * Pink strong color. + */ public static final Color PINK = new Color(255, 0, 132); + /** + * Light pink strong color. + */ public static final Color LIGHT_PINK = new Color(255, 117, 198); private Strong() { diff --git a/src/main/java/de/chojo/repbot/util/EmojiDebug.java b/src/main/java/de/chojo/repbot/util/EmojiDebug.java index dfa28e9b0..4fcee7121 100644 --- a/src/main/java/de/chojo/repbot/util/EmojiDebug.java +++ b/src/main/java/de/chojo/repbot/util/EmojiDebug.java @@ -5,17 +5,59 @@ */ package de.chojo.repbot.util; +/** + * Utility class for emoji debug symbols. + */ public final class EmojiDebug { + /** + * Indicates that a thank word was found. + */ public static final String FOUND_THANKWORD = "👀"; + + /** + * Indicates that only a cooldown is active. + */ public static final String ONLY_COOLDOWN = "💤"; + + /** + * Indicates that the context is empty. + */ public static final String EMPTY_CONTEXT = "🔍"; + + /** + * Indicates that the target is not in the context. + */ public static final String TARGET_NOT_IN_CONTEXT = "❓"; + + /** + * Indicates that the donor is not in the context. + */ public static final String DONOR_NOT_IN_CONTEXT = "❔"; + + /** + * Indicates that the context is too old. + */ public static final String TOO_OLD = "🕛"; + + /** + * Indicates that a prompt was made. + */ public static final String PROMPTED = "🗨"; + + /** + * Indicates that the receiver limit was reached. + */ public static final String RECEIVER_LIMIT = "✋"; + + /** + * Indicates that the donor limit was reached. + */ public static final String DONOR_LIMIT = "🤲"; + /** + * Private constructor to prevent instantiation. + * Throws an UnsupportedOperationException if called. + */ private EmojiDebug() { throw new UnsupportedOperationException("This is a utility class."); } diff --git a/src/main/java/de/chojo/repbot/util/FilterUtil.java b/src/main/java/de/chojo/repbot/util/FilterUtil.java index ccf1e6247..c3bf5d246 100644 --- a/src/main/java/de/chojo/repbot/util/FilterUtil.java +++ b/src/main/java/de/chojo/repbot/util/FilterUtil.java @@ -12,22 +12,36 @@ import java.util.List; import java.util.stream.Collectors; +/** + * Utility class for filtering text channels in a guild based on permissions. + */ public final class FilterUtil { + /** + * Private constructor to prevent instantiation. + * Throws an UnsupportedOperationException if called. + */ private FilterUtil() { throw new UnsupportedOperationException("This is a utility class."); } /** - * Get all channel where the bot user can write and read. + * Retrieves all text channels in the guild where the bot user has both read and write permissions. * - * @param guild guild - * @return list of accessable text channel + * @param guild the guild to filter channels from + * @return a list of accessible text channels */ public static List getAccessableTextChannel(Guild guild) { return filterChannelByPermission(guild, Permission.VIEW_CHANNEL, Permission.MESSAGE_SEND); } + /** + * Filters the text channels in the guild based on the specified permissions. + * + * @param guild the guild to filter channels from + * @param permissions the permissions to check for each channel + * @return a list of text channels that the bot user has the specified permissions for + */ public static List filterChannelByPermission(Guild guild, Permission... permissions) { var self = guild.getSelfMember(); return guild.getTextChannels().stream().filter(textChannel -> self.hasPermission(textChannel, permissions)) diff --git a/src/main/java/de/chojo/repbot/util/Guilds.java b/src/main/java/de/chojo/repbot/util/Guilds.java index a493c2ab8..d3f9d8553 100644 --- a/src/main/java/de/chojo/repbot/util/Guilds.java +++ b/src/main/java/de/chojo/repbot/util/Guilds.java @@ -7,11 +7,25 @@ import net.dv8tion.jda.api.entities.Guild; +/** + * Utility class for guild-related operations. + */ public final class Guilds { + + /** + * Private constructor to prevent instantiation. + * Throws an UnsupportedOperationException if called. + */ private Guilds() { throw new UnsupportedOperationException("This is a utility class."); } + /** + * Generates a pretty name for the guild, including its name and ID. + * + * @param guild the Guild instance + * @return a formatted string containing the guild's name and ID + */ public static String prettyName(Guild guild) { return String.format("%s (%s)", guild.getName(), guild.getIdLong()); } diff --git a/src/main/java/de/chojo/repbot/util/LogNotify.java b/src/main/java/de/chojo/repbot/util/LogNotify.java index e44da93f8..1293efb4b 100644 --- a/src/main/java/de/chojo/repbot/util/LogNotify.java +++ b/src/main/java/de/chojo/repbot/util/LogNotify.java @@ -9,24 +9,38 @@ import org.slf4j.Marker; import org.slf4j.MarkerFactory; +/** + * Utility class for creating and managing log markers. + */ public final class LogNotify { /** - * Will be send to error-log channel. + * Marker for notifications to be sent to the error-log channel. */ public static final Marker NOTIFY_ADMIN = createMarker("NOTIFY_ADMIN"); /** - * Will be sent to status-log. + * Marker for notifications to be sent to the status-log. */ public static final Marker STATUS = createMarker("STATUS"); /** - * Currently unused. + * Marker currently unused. */ public static final Marker DISCORD = createMarker("DISCORD"); + /** + * Private constructor to prevent instantiation. + * Throws an UnsupportedOperationException if called. + */ private LogNotify() { throw new UnsupportedOperationException("This is a utility class."); } + /** + * Creates a new marker with the specified name and optional child markers. + * + * @param name the name of the marker + * @param children optional child markers to add to the created marker + * @return the created marker + */ private static Marker createMarker(@NotNull String name, @NotNull Marker... children) { var marker = MarkerFactory.getMarker(name); for (var child : children) { diff --git a/src/main/java/de/chojo/repbot/util/Messages.java b/src/main/java/de/chojo/repbot/util/Messages.java index ac141db96..f4ea6e908 100644 --- a/src/main/java/de/chojo/repbot/util/Messages.java +++ b/src/main/java/de/chojo/repbot/util/Messages.java @@ -18,13 +18,26 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Utility class for handling message reactions. + */ public final class Messages { private static final Logger log = getLogger(Messages.class); + /** + * Private constructor to prevent instantiation. + */ private Messages() { throw new UnsupportedOperationException("This is a utility class."); } + /** + * Adds a reaction to a message based on the settings. + * + * @param message the message to add a reaction to + * @param refMessage an optional reference message to also add the reaction to + * @param settings the settings containing the reaction information + */ public static void markMessage(Message message, @Nullable Message refMessage, Settings settings) { var reaction = settings.thanking().reactions().mainReaction(); if (settings.thanking().reactions().reactionIsEmote()) { @@ -38,6 +51,12 @@ public static void markMessage(Message message, @Nullable Message refMessage, Se } } + /** + * Adds an emoji reaction to a message. + * + * @param message the message to add a reaction to + * @param emote the emoji to add as a reaction + */ public static void markMessage(Message message, Emoji emote) { if (PermissionUtil.checkPermission(message.getGuildChannel().getPermissionContainer(), message.getGuild() .getSelfMember(), Permission.MESSAGE_ADD_REACTION)) { @@ -45,6 +64,12 @@ public static void markMessage(Message message, Emoji emote) { } } + /** + * Adds a Unicode emoji reaction to a message. + * + * @param message the message to add a reaction to + * @param emoji the Unicode emoji to add as a reaction + */ public static void markMessage(Message message, String emoji) { if (PermissionUtil.checkPermission(message.getGuildChannel().getPermissionContainer(), message.getGuild() .getSelfMember(), Permission.MESSAGE_ADD_REACTION)) { @@ -52,6 +77,11 @@ public static void markMessage(Message message, String emoji) { } } + /** + * Handles the reaction addition action, ignoring specific error responses. + * + * @param action the RestAction to handle + */ private static void handleMark(RestAction action) { action.queue(RestAction.getDefaultSuccess(), ErrorResponseException.ignore( diff --git a/src/main/java/de/chojo/repbot/util/PermissionErrorHandler.java b/src/main/java/de/chojo/repbot/util/PermissionErrorHandler.java index 787760c47..937ba7045 100644 --- a/src/main/java/de/chojo/repbot/util/PermissionErrorHandler.java +++ b/src/main/java/de/chojo/repbot/util/PermissionErrorHandler.java @@ -18,11 +18,22 @@ import net.dv8tion.jda.api.sharding.ShardManager; import net.dv8tion.jda.internal.utils.PermissionUtil; +/** + * Utility class for handling permission errors. + */ public final class PermissionErrorHandler { private PermissionErrorHandler() { throw new UnsupportedOperationException("This is a utility class."); } + /** + * Handles an InsufficientPermissionException by sending a permission error message to the appropriate channel. + * + * @param permissionException the exception to handle + * @param shardManager the shard manager + * @param localizer the localization context + * @param configuration the configuration + */ public static void handle(InsufficientPermissionException permissionException, ShardManager shardManager, LocalizationContext localizer, Configuration configuration) { var permission = permissionException.getPermission(); @@ -32,6 +43,14 @@ public static void handle(InsufficientPermissionException permissionException, S sendPermissionError(channel, permission, localizer, configuration); } + /** + * Handles an InsufficientPermissionException by sending a permission error message to the appropriate channel. + * + * @param permissionException the exception to handle + * @param guild the guild + * @param localizer the localization context + * @param configuration the configuration + */ public static void handle(InsufficientPermissionException permissionException, Guild guild, LocalizationContext localizer, Configuration configuration) { var permission = permissionException.getPermission(); @@ -40,6 +59,14 @@ public static void handle(InsufficientPermissionException permissionException, G sendPermissionError(channel, permission, localizer, configuration); } + /** + * Handles an InsufficientPermissionException by sending a permission error message to the appropriate channel. + * + * @param permissionException the exception to handle + * @param channel the channel + * @param localizer the localization context + * @param configuration the configuration + */ public static void handle(InsufficientPermissionException permissionException, GuildMessageChannel channel, LocalizationContext localizer, Configuration configuration) { var permission = permissionException.getPermission(); @@ -47,6 +74,14 @@ public static void handle(InsufficientPermissionException permissionException, G sendPermissionError(channel, permission, localizer, configuration); } + /** + * Sends a permission error message to the specified channel. + * + * @param channel the channel to send the message to + * @param permission the missing permission + * @param localizer the localization context + * @param configuration the configuration + */ public static void sendPermissionError(GuildMessageChannel channel, Permission permission, LocalizationContext localizer, Configuration configuration) { var guild = channel.getGuild(); @@ -92,6 +127,13 @@ public static void assertPermissions(GuildMessageChannel channel, Permission... } } + /** + * Assert that the user has permissions. + * + * @param guild guild to check + * @param permissions permissions to check + * @throws InsufficientPermissionException when the bot user doesnt have a permission + */ public static void assertPermissions(Guild guild, Permission... permissions) throws InsufficientPermissionException { var self = guild.getSelfMember(); for (var permission : permissions) { diff --git a/src/main/java/de/chojo/repbot/util/Roles.java b/src/main/java/de/chojo/repbot/util/Roles.java index e311d5136..3ea0508e2 100644 --- a/src/main/java/de/chojo/repbot/util/Roles.java +++ b/src/main/java/de/chojo/repbot/util/Roles.java @@ -7,11 +7,24 @@ import net.dv8tion.jda.api.entities.Role; +/** + * Utility class for handling roles. + */ public final class Roles { + /** + * Private constructor to prevent instantiation. + * Throws UnsupportedOperationException if called. + */ private Roles() { throw new UnsupportedOperationException("This is a utility class."); } + /** + * Returns a pretty string representation of the role. + * + * @param role the role to format + * @return the formatted string representation of the role + */ public static String prettyName(Role role) { return String.format("%s (%s)", role.getName(), role.getIdLong()); } diff --git a/src/main/java/de/chojo/repbot/util/Text.java b/src/main/java/de/chojo/repbot/util/Text.java index a115085f0..f25bcaa2e 100644 --- a/src/main/java/de/chojo/repbot/util/Text.java +++ b/src/main/java/de/chojo/repbot/util/Text.java @@ -14,58 +14,161 @@ import java.time.LocalTime; import java.time.format.DateTimeFormatter; +/** + * Utility class for text-related operations. + */ public final class Text { + /** + * Constant representing an empty character. + */ private static final String EMPTY = "_"; + + /** + * Constant representing a full block character. + */ private static final String FULL = "█"; + + /** + * Constant representing the color orange in ANSI escape codes. + */ private static final String ORANGE = "\u001b[0;33m"; + + /** + * Constant representing the color white in ANSI escape codes. + */ private static final String WHITE = "\u001b[0;37;47m"; + + /** + * Private constructor to prevent instantiation of this utility class. + */ private Text() { throw new UnsupportedOperationException("This is a utility class."); } + /** + * Generates a progress bar string. + * + * @param percent the percentage of completion + * @param tiles the total number of tiles in the progress bar + * @return the generated progress bar string + */ public static String progressBar(double percent, int tiles) { var progressBar = StringUtils.repeat(FULL, (int) Math.round(percent * tiles)) + WHITE; return ORANGE + StringUtils.rightPad(progressBar, tiles + WHITE.length(), EMPTY); } + /** + * Date formatter for the pattern "yyyy-MM-dd". + */ private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + /** + * Date formatter for the pattern "yyyy-MM". + */ private static final DateTimeFormatter MONTH = DateTimeFormatter.ofPattern("yyyy-MM"); + + /** + * Date-time formatter for the pattern "yyyy-MM-dd HH:mm". + */ private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + /** + * Time formatter for the pattern "HH:mm". + */ private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm"); + /** + * Formats a LocalDate object to a string. + * + * @param date the LocalDate object + * @return the formatted date string + */ public static String date(LocalDate date) { return DATE_FORMATTER.format(date); } + /** + * Formats a LocalDateTime object to a string. + * + * @param date the LocalDateTime object + * @return the formatted date string + */ public static String date(LocalDateTime date) { return DATE_FORMATTER.format(date); } + /** + * Formats a LocalDate object to a string representing the month. + * + * @param date the LocalDate object + * @return the formatted month string + */ public static String month(LocalDate date) { return MONTH.format(date); } + /** + * Formats a LocalDateTime object to a date-time string. + * + * @param dateTime the LocalDateTime object + * @return the formatted date-time string + */ public static String dateTime(LocalDateTime dateTime) { return DATE_TIME_FORMATTER.format(dateTime); } + /** + * Formats a LocalTime object to a time string. + * + * @param time the LocalTime object + * @return the formatted time string + */ public static String time(LocalTime time) { return TIME_FORMATTER.format(time); } + /** + * Formats a LocalDateTime object to a time string. + * + * @param time the LocalDateTime object + * @return the formatted time string + */ public static String time(LocalDateTime time) { return TIME_FORMATTER.format(time); } + /** + * Retrieves a localized boolean message based on the value. + * + * @param context the event context + * @param value the boolean value + * @param whenTrue the message when the value is true + * @param whenFalse the message when the value is false + * @return the localized boolean message + */ public static String getBooleanMessage(EventContext context, boolean value, String whenTrue, String whenFalse) { return context.localize(value ? whenTrue : whenFalse); } + /** + * Retrieves a localized setting message. + * + * @param locale the locale key + * @param object the object to include in the message + * @return the localized setting message + */ public static String getSetting(@PropertyKey(resourceBundle = "locale") String locale, Object object) { return String.format("$%s$: %s", locale, object); } + /** + * Retrieves a localized setting message based on the enabled state. + * + * @param locale the locale key + * @param enabled the enabled state + * @return the localized setting message + */ public static String getSetting(@PropertyKey(resourceBundle = "locale") String locale, boolean enabled) { return String.format("$%s$: $%s$", locale, enabled ? "words.enabled" : "words.disabled"); } diff --git a/src/main/java/de/chojo/repbot/web/Api.java b/src/main/java/de/chojo/repbot/web/Api.java index 240671572..28798e2ec 100644 --- a/src/main/java/de/chojo/repbot/web/Api.java +++ b/src/main/java/de/chojo/repbot/web/Api.java @@ -6,7 +6,7 @@ package de.chojo.repbot.web; import de.chojo.repbot.dao.provider.Metrics; -import de.chojo.repbot.web.erros.ApiException; +import de.chojo.repbot.web.error.ApiException; import de.chojo.repbot.web.routes.v1.MetricsRoute; import io.javalin.Javalin; import org.slf4j.Logger; @@ -15,16 +15,28 @@ import static io.javalin.apibuilder.ApiBuilder.path; import static org.slf4j.LoggerFactory.getLogger; +/** + * The Api class initializes and configures the Javalin web server with routes and exception handling. + */ public class Api { private static final Logger log = getLogger(Api.class); private final Javalin javalin; private final MetricsRoute metricsRoute; + /** + * Constructs an Api instance with the specified Javalin instance and Metrics provider. + * + * @param javalin the Javalin instance to be used + * @param metrics the Metrics provider + */ public Api(Javalin javalin, Metrics metrics) { this.javalin = javalin; metricsRoute = new MetricsRoute(metrics); } + /** + * Initializes the API by setting up exception handling and routes. + */ public void init() { javalin.exception(ApiException.class, (err, ctx) -> ctx.result(err.getMessage()).status(err.status())); javalin.routes(() -> { diff --git a/src/main/java/de/chojo/repbot/web/error/ApiException.java b/src/main/java/de/chojo/repbot/web/error/ApiException.java index c6bfea804..1873371a0 100644 --- a/src/main/java/de/chojo/repbot/web/error/ApiException.java +++ b/src/main/java/de/chojo/repbot/web/error/ApiException.java @@ -3,18 +3,35 @@ * * Copyright (C) RainbowDashLabs and Contributor */ -package de.chojo.repbot.web.erros; +package de.chojo.repbot.web.error; import io.javalin.http.HttpCode; +/** + * Custom exception class for API errors. + */ public class ApiException extends RuntimeException { + /** + * The HTTP status code associated with this exception. + */ private final HttpCode status; + /** + * Constructs a new ApiException with the specified HTTP status code and message. + * + * @param status the HTTP status code + * @param message the detail message + */ public ApiException(HttpCode status, String message) { super(message); this.status = status; } + /** + * Returns the HTTP status code associated with this exception. + * + * @return the HTTP status code + */ public HttpCode status() { return status; } diff --git a/src/main/java/de/chojo/repbot/web/routes/RoutesBuilder.java b/src/main/java/de/chojo/repbot/web/routes/RoutesBuilder.java index e30445112..996493b59 100644 --- a/src/main/java/de/chojo/repbot/web/routes/RoutesBuilder.java +++ b/src/main/java/de/chojo/repbot/web/routes/RoutesBuilder.java @@ -5,6 +5,12 @@ */ package de.chojo.repbot.web.routes; +/** + * Interface for building routes. + */ public interface RoutesBuilder { + /** + * Builds the routes. + */ void buildRoutes(); } diff --git a/src/main/java/de/chojo/repbot/web/routes/v1/MetricsHolder.java b/src/main/java/de/chojo/repbot/web/routes/v1/MetricsHolder.java index e8e52cf53..d6c350a73 100644 --- a/src/main/java/de/chojo/repbot/web/routes/v1/MetricsHolder.java +++ b/src/main/java/de/chojo/repbot/web/routes/v1/MetricsHolder.java @@ -6,7 +6,7 @@ package de.chojo.repbot.web.routes.v1; import de.chojo.repbot.dao.provider.Metrics; -import de.chojo.repbot.web.erros.ApiException; +import de.chojo.repbot.web.error.ApiException; import de.chojo.repbot.web.routes.RoutesBuilder; import de.chojo.repbot.web.routes.v1.metrics.MetricCache; import io.javalin.http.Context; @@ -17,20 +17,40 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Abstract class for handling metrics-related routes. + */ public abstract class MetricsHolder implements RoutesBuilder { private static final Logger log = getLogger(MetricsHolder.class); private final MetricCache cache; private final Metrics metrics; + /** + * Constructs a new MetricsHolder with the specified cache and metrics. + * + * @param cache the metric cache + * @param metrics the metrics provider + */ public MetricsHolder(MetricCache cache, Metrics metrics) { this.cache = cache; this.metrics = metrics; } + /** + * Returns the metrics provider. + * + * @return the metrics provider + */ public Metrics metrics() { return metrics; } + /** + * Writes an image to the HTTP context. + * + * @param ctx the HTTP context + * @param png the image data in PNG format + */ protected void writeImage(Context ctx, byte[] png) { ctx.header("Content-Disposition", "filename=\"stats.png\""); ctx.header("X-Content-Type-Options", "nosniff"); @@ -39,6 +59,14 @@ protected void writeImage(Context ctx, byte[] png) { ctx.result(png).status(HttpStatus.OK_200); } + /** + * Retrieves and validates the offset parameter from the context. + * + * @param context the HTTP context + * @param max the maximum allowed value for the offset + * @return the validated offset value + * @throws ApiException if the offset is not a valid number or is out of range + */ protected int offset(Context context, int max) { var param = context.pathParam("offset"); try { @@ -50,6 +78,14 @@ protected int offset(Context context, int max) { } } + /** + * Retrieves and validates the count parameter from the context. + * + * @param context the HTTP context + * @param max the maximum allowed value for the count + * @return the validated count value + * @throws ApiException if the count is not a valid number or is out of range + */ protected int count(Context context, int max) { var param = context.pathParam("count"); try { @@ -61,6 +97,14 @@ protected int count(Context context, int max) { } } + /** + * Asserts that a value is within the specified range. + * + * @param value the value to check + * @param min the minimum allowed value + * @param max the maximum allowed value + * @throws ApiException if the value is out of range + */ private void assertSize(int value, int min, int max) { if (value < min) { throw new ApiException(HttpCode.BAD_REQUEST, String.format("Value %s is too small. Min: %s", value, min)); @@ -70,6 +114,12 @@ private void assertSize(int value, int min, int max) { } } + /** + * Wraps a handler with caching functionality. + * + * @param handler the handler to wrap + * @return the wrapped handler + */ public Handler cache(Handler handler) { return cache.cache(handler); } diff --git a/src/main/java/de/chojo/repbot/web/routes/v1/MetricsRoute.java b/src/main/java/de/chojo/repbot/web/routes/v1/MetricsRoute.java index e9e44ddfa..bcd54d282 100644 --- a/src/main/java/de/chojo/repbot/web/routes/v1/MetricsRoute.java +++ b/src/main/java/de/chojo/repbot/web/routes/v1/MetricsRoute.java @@ -14,18 +14,56 @@ import de.chojo.repbot.web.routes.v1.metrics.Users; import io.swagger.v3.oas.models.parameters.Parameter; +/** + * Class for building and managing metric-related routes. + */ public class MetricsRoute implements RoutesBuilder { + /** + * Maximum offset for hours. + */ public static final int MAX_HOUR_OFFSET = 336; + + /** + * Maximum offset for days. + */ public static final int MAX_DAY_OFFSET = 60; + + /** + * Maximum offset for weeks. + */ public static final int MAX_WEEK_OFFSET = 52; + + /** + * Maximum offset for months. + */ public static final int MAX_MONTH_OFFSET = 24; + + /** + * Maximum offset for years. + */ public static final int MAX_YEAR_OFFSET = 2; + /** + * Maximum count for hours. + */ public static final int MAX_HOURS = 120; + + /** + * Maximum count for days. + */ public static final int MAX_DAYS = 120; + + /** + * Maximum count for weeks. + */ public static final int MAX_WEEKS = 104; + + /** + * Maximum count for months. + */ public static final int MAX_MONTH = 48; + private final Reputation reputation; private final Commands commands; private final Messages messages; @@ -33,6 +71,11 @@ public class MetricsRoute implements RoutesBuilder { private final MetricCache cache; private final Service service; + /** + * Constructs a new MetricsRoute with the specified metrics provider. + * + * @param metrics the metrics provider + */ public MetricsRoute(de.chojo.repbot.dao.provider.Metrics metrics) { cache = new MetricCache(); reputation = new Reputation(metrics, cache); @@ -42,7 +85,9 @@ public MetricsRoute(de.chojo.repbot.dao.provider.Metrics metrics) { service = new Service(metrics, cache); } - + /** + * Builds the routes for the metrics. + */ @Override public void buildRoutes() { cache.buildRoutes(); @@ -53,50 +98,115 @@ public void buildRoutes() { service.buildRoutes(); } + /** + * Sets the documentation for the offset parameter. + * + * @param parameter the parameter to set the documentation for + * @param resolution the resolution of the offset + * @param maxValue the maximum value for the offset + */ private static void offsetDoc(Parameter parameter, String resolution, int maxValue) { setParameter(parameter, "%s offset. 0 is current %s. Max value is %s".formatted(resolution, resolution.toLowerCase(), maxValue)); } + /** + * Sets the documentation for the day offset parameter. + * + * @param p the parameter to set the documentation for + */ public static void offsetDayDoc(Parameter p) { offsetDoc(p, "Day", MAX_DAY_OFFSET); } + /** + * Sets the documentation for the hour offset parameter. + * + * @param p the parameter to set the documentation for + */ public static void offsetHourDoc(Parameter p) { offsetDoc(p, "Hour", MAX_HOUR_OFFSET); } + /** + * Sets the documentation for the week offset parameter. + * + * @param p the parameter to set the documentation for + */ public static void offsetWeekDoc(Parameter p) { offsetDoc(p, "Week", MAX_WEEK_OFFSET); } + /** + * Sets the documentation for the month offset parameter. + * + * @param p the parameter to set the documentation for + */ public static void offsetMonthDoc(Parameter p) { offsetDoc(p, "Month", MAX_MONTH_OFFSET); } + /** + * Sets the documentation for the year offset parameter. + * + * @param p the parameter to set the documentation for + */ public static void offsetYearDoc(Parameter p) { offsetDoc(p, "Year", MAX_YEAR_OFFSET); } + /** + * Sets the documentation for the count parameter. + * + * @param parameter the parameter to set the documentation for + * @param resolution the resolution of the count + * @param maxValue the maximum value for the count + */ private static void countDoc(Parameter parameter, String resolution, int maxValue) { setParameter(parameter, "%s count. Amount of previously %s in the chart. Max value is %s".formatted(resolution, resolution.toLowerCase(), maxValue)); } + /** + * Sets the documentation for the hour count parameter. + * + * @param p the parameter to set the documentation for + */ public static void countHourDoc(Parameter p) { countDoc(p, "Hours", MAX_HOURS); } + /** + * Sets the documentation for the day count parameter. + * + * @param p the parameter to set the documentation for + */ public static void countDayDoc(Parameter p) { countDoc(p, "Days", MAX_DAYS); } + /** + * Sets the documentation for the week count parameter. + * + * @param p the parameter to set the documentation for + */ public static void countWeekDoc(Parameter p) { countDoc(p, "Weeks", MAX_WEEKS); } + /** + * Sets the documentation for the month count parameter. + * + * @param p the parameter to set the documentation for + */ public static void countMonthDoc(Parameter p) { countDoc(p, "Months", MAX_MONTH); } + /** + * Sets the description for the parameter. + * + * @param p the parameter to set the description for + * @param description the description to set + */ private static void setParameter(Parameter p, String description) { p.setDescription(description); } diff --git a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Commands.java b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Commands.java index f218ee4a7..e17dde0aa 100644 --- a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Commands.java +++ b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Commands.java @@ -20,11 +20,25 @@ import static io.javalin.apibuilder.ApiBuilder.get; import static io.javalin.apibuilder.ApiBuilder.path; +/** + * Handles the metrics related to commands. + */ public class Commands extends MetricsHolder { + /** + * Constructs a Commands instance with the specified metrics and cache. + * + * @param metrics the metrics provider + * @param cache the metric cache + */ public Commands(Metrics metrics, MetricCache cache) { super(cache, metrics); } + /** + * Handles the request for command usage statistics for a week. + * + * @param ctx the context of the request + */ public void usageWeek(Context ctx) { var stats = metrics().commands().week(offset(ctx, MAX_WEEK_OFFSET)); if ("application/json".equals(ctx.header("Accept"))) { @@ -34,6 +48,11 @@ public void usageWeek(Context ctx) { } } + /** + * Handles the request for command usage statistics for a month. + * + * @param ctx the context of the request + */ public void usageMonth(Context ctx) { var stats = metrics().commands().month(offset(ctx, MAX_MONTH_OFFSET)); if ("application/json".equals(ctx.header("Accept"))) { @@ -43,6 +62,11 @@ public void usageMonth(Context ctx) { } } + /** + * Handles the request for the count of commands executed per week. + * + * @param ctx the context of the request + */ public void countWeek(Context ctx) { var stats = metrics().commands().week(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -52,6 +76,11 @@ public void countWeek(Context ctx) { } } + /** + * Handles the request for the count of commands executed per month. + * + * @param ctx the context of the request + */ public void countMonth(Context ctx) { var stats = metrics().commands().month(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -61,13 +90,16 @@ public void countMonth(Context ctx) { } } + /** + * Builds the routes for the commands metrics. + */ @Override public void buildRoutes() { path("commands", () -> { path("count", () -> { get("week/{offset}/{count}", OpenApiBuilder.documented(OpenApiBuilder.document() .operation(op -> { - op.summary("Get the amount of exectued commands per week."); + op.summary("Get the amount of executed commands per week."); }) .result("200", byte[].class, "image/png") .result("200", CommandsStatistic.class, "application/json") @@ -76,7 +108,7 @@ public void buildRoutes() { cache(this::countWeek))); get("month/{offset}/{count}", OpenApiBuilder.documented(OpenApiBuilder.document() .operation(op -> { - op.summary("Get the amount of exectued commands per month."); + op.summary("Get the amount of executed commands per month."); }) .result("200", byte[].class, "image/png") .result("200", CommandsStatistic.class, "application/json") diff --git a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Messages.java b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Messages.java index 75ba93105..9cd767bf9 100644 --- a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Messages.java +++ b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Messages.java @@ -23,11 +23,25 @@ import static io.javalin.apibuilder.ApiBuilder.get; import static io.javalin.apibuilder.ApiBuilder.path; +/** + * Handles the metrics related to messages. + */ public class Messages extends MetricsHolder { + /** + * Constructs a new Messages handler. + * + * @param metrics the Metrics provider + * @param cache the MetricCache + */ public Messages(Metrics metrics, MetricCache cache) { super(cache, metrics); } + /** + * Handles the request to get the count of messages analyzed per hour. + * + * @param ctx the Javalin context + */ public void countHour(Context ctx) { var stats = metrics().messages().hour(offset(ctx, MAX_HOUR_OFFSET), count(ctx, MAX_HOURS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -37,6 +51,11 @@ public void countHour(Context ctx) { } } + /** + * Handles the request to get the count of messages analyzed per day. + * + * @param ctx the Javalin context + */ public void countDay(Context ctx) { var stats = metrics().messages().day(offset(ctx, MAX_DAY_OFFSET), count(ctx, MAX_DAYS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -46,6 +65,11 @@ public void countDay(Context ctx) { } } + /** + * Handles the request to get the count of messages analyzed per week. + * + * @param ctx the Javalin context + */ public void countWeek(Context ctx) { var stats = metrics().messages().week(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -55,6 +79,11 @@ public void countWeek(Context ctx) { } } + /** + * Handles the request to get the count of messages analyzed per month. + * + * @param ctx the Javalin context + */ public void countMonth(Context ctx) { var stats = metrics().messages().month(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -64,6 +93,11 @@ public void countMonth(Context ctx) { } } + /** + * Handles the request to get the total count of messages analyzed per day. + * + * @param ctx the Javalin context + */ public void totalDay(Context ctx) { var stats = metrics().messages().totalDay(offset(ctx, MAX_DAY_OFFSET), count(ctx, MAX_DAYS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -73,6 +107,11 @@ public void totalDay(Context ctx) { } } + /** + * Handles the request to get the total count of messages analyzed per week. + * + * @param ctx the Javalin context + */ public void totalWeek(Context ctx) { var stats = metrics().messages().totalWeek(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -82,6 +121,11 @@ public void totalWeek(Context ctx) { } } + /** + * Handles the request to get the total count of messages analyzed per month. + * + * @param ctx the Javalin context + */ public void totalMonth(Context ctx) { var stats = metrics().messages().totalMonth(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -91,6 +135,9 @@ public void totalMonth(Context ctx) { } } + /** + * Builds the routes for message metrics. + */ @Override public void buildRoutes() { path("messages", () -> { diff --git a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/MetricCache.java b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/MetricCache.java index 04fc7e9cb..39a528bee 100644 --- a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/MetricCache.java +++ b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/MetricCache.java @@ -22,6 +22,9 @@ import static io.javalin.apibuilder.ApiBuilder.after; import static org.slf4j.LoggerFactory.getLogger; +/** + * Handles caching of metric responses to improve performance and reduce load. + */ public class MetricCache implements RoutesBuilder { private static final Logger log = getLogger(MetricCache.class); private final RateLimiter rateLimiter; @@ -30,10 +33,19 @@ public class MetricCache implements RoutesBuilder { .maximumSize(100) .build(); + /** + * Constructs a MetricCache with a rate limiter. + */ public MetricCache() { rateLimiter = new RateLimiter(TimeUnit.MINUTES); } + /** + * Returns a handler that caches the response of the given handler. + * + * @param supplier the handler whose response should be cached + * @return a handler that caches the response + */ public Handler cache(Handler supplier) { return ctx -> { var cacheKey = new CacheKey(ctx); @@ -50,6 +62,9 @@ public Handler cache(Handler supplier) { }; } + /** + * Builds the routes for caching metric responses. + */ @Override public void buildRoutes() { after(ctx -> { @@ -61,6 +76,9 @@ public void buildRoutes() { }); } + /** + * Represents a cached response. + */ private static class ResponseCache { String route; String accept; @@ -69,6 +87,11 @@ private static class ResponseCache { int status; byte[] body; + /** + * Constructs a ResponseCache from the given context. + * + * @param ctx the context + */ ResponseCache(Context ctx) { route = ctx.path(); accept = ctx.header("Accept"); @@ -83,6 +106,11 @@ private static class ResponseCache { } } + /** + * Applies the cached response to the given context. + * + * @param ctx the context + */ void apply(Context ctx) { ctx.status(status); for (var header : header.entrySet()) { @@ -94,10 +122,18 @@ void apply(Context ctx) { } } + /** + * Represents a key for caching responses. + */ private static class CacheKey { String route; String accept; + /** + * Constructs a CacheKey from the given context. + * + * @param ctx the context + */ CacheKey(Context ctx) { route = ctx.path(); accept = ctx.header("Accept"); diff --git a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Reputation.java b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Reputation.java index a0b445105..89a0c9604 100644 --- a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Reputation.java +++ b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Reputation.java @@ -22,13 +22,24 @@ import static io.javalin.apibuilder.ApiBuilder.get; import static io.javalin.apibuilder.ApiBuilder.path; +/** + * Class for handling reputation metrics routes. + */ public class Reputation extends MetricsHolder { + /** + * Constructs a new Reputation instance. + * + * @param metrics the metrics provider + * @param cache the metric cache + */ public Reputation(Metrics metrics, MetricCache cache) { super(cache, metrics); } - /* - This function is broken, but I don't know how to fix it. + /** + * Retrieves the reputation count per week. + * + * @param ctx the Javalin context */ public void countWeek(Context ctx) { var stats = metrics().reputation().week(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); @@ -39,6 +50,11 @@ public void countWeek(Context ctx) { } } + /** + * Retrieves the reputation count per month. + * + * @param ctx the Javalin context + */ public void countMonth(Context ctx) { var stats = metrics().reputation().month(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -48,6 +64,11 @@ public void countMonth(Context ctx) { } } + /** + * Retrieves the reputation count per week by type. + * + * @param ctx the Javalin context + */ public void countTypeWeek(Context ctx) { var stats = metrics().reputation().typeWeek(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -57,6 +78,11 @@ public void countTypeWeek(Context ctx) { } } + /** + * Retrieves the reputation count per month by type. + * + * @param ctx the Javalin context + */ public void countTypeMonth(Context ctx) { var stats = metrics().reputation().typeMonth(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -66,6 +92,11 @@ public void countTypeMonth(Context ctx) { } } + /** + * Retrieves the total reputation per week. + * + * @param ctx the Javalin context + */ public void totalWeek(Context ctx) { var stats = metrics().reputation().totalWeek(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -75,6 +106,11 @@ public void totalWeek(Context ctx) { } } + /** + * Retrieves the total reputation per month. + * + * @param ctx the Javalin context + */ public void totalMonth(Context ctx) { var stats = metrics().reputation().totalMonth(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -84,6 +120,11 @@ public void totalMonth(Context ctx) { } } + /** + * Retrieves the total reputation per week by type. + * + * @param ctx the Javalin context + */ public void totalTypeWeek(Context ctx) { var stats = metrics().reputation().typeTotalWeek(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -93,6 +134,11 @@ public void totalTypeWeek(Context ctx) { } } + /** + * Retrieves the total reputation per month by type. + * + * @param ctx the Javalin context + */ public void totalTypeMonth(Context ctx) { var stats = metrics().reputation().typeTotalMonth(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -102,6 +148,11 @@ public void totalTypeMonth(Context ctx) { } } + /** + * Retrieves the reputation changes per week. + * + * @param ctx the Javalin context + */ public void changesWeek(Context ctx) { var stats = metrics().reputation().weekChanges(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -111,6 +162,11 @@ public void changesWeek(Context ctx) { } } + /** + * Retrieves the reputation changes per month. + * + * @param ctx the Javalin context + */ public void changesMonth(Context ctx) { var stats = metrics().reputation().monthChanges(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -120,6 +176,11 @@ public void changesMonth(Context ctx) { } } + /** + * Retrieves the reputation given per day of the week (weekly average). + * + * @param ctx the Javalin context + */ public void dowWeek(Context ctx) { var stats = metrics().reputation().dowWeek(offset(ctx, MAX_WEEK_OFFSET)); if ("application/json".equals(ctx.header("Accept"))) { @@ -129,6 +190,11 @@ public void dowWeek(Context ctx) { } } + /** + * Retrieves the reputation given per day of the week (monthly average). + * + * @param ctx the Javalin context + */ public void dowMonth(Context ctx) { var stats = metrics().reputation().dowMonth(offset(ctx, MAX_MONTH_OFFSET)); if ("application/json".equals(ctx.header("Accept"))) { @@ -138,6 +204,11 @@ public void dowMonth(Context ctx) { } } + /** + * Retrieves the reputation given per day of the week (yearly average). + * + * @param ctx the Javalin context + */ public void dowYear(Context ctx) { var stats = metrics().reputation().dowYear(offset(ctx, MAX_YEAR_OFFSET)); if ("application/json".equals(ctx.header("Accept"))) { @@ -147,6 +218,9 @@ public void dowYear(Context ctx) { } } + /** + * Builds the routes for reputation metrics. + */ @Override public void buildRoutes() { path("reputation", () -> { diff --git a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Service.java b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Service.java index b86ba4450..a6d2004cb 100644 --- a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Service.java +++ b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Service.java @@ -23,11 +23,25 @@ import static io.javalin.apibuilder.ApiBuilder.get; import static io.javalin.apibuilder.ApiBuilder.path; +/** + * Service class for handling metrics related to interactions. + */ public class Service extends MetricsHolder { + /** + * Constructs a new Service. + * + * @param metrics the metrics provider + * @param cache the metric cache + */ public Service(Metrics metrics, MetricCache cache) { super(cache, metrics); } + /** + * Handles the request to get the count of handled interactions per hour. + * + * @param ctx the context of the request + */ public void countHour(Context ctx) { var stats = metrics().service().hour(offset(ctx, MAX_HOUR_OFFSET), count(ctx, MAX_HOURS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -37,6 +51,11 @@ public void countHour(Context ctx) { } } + /** + * Handles the request to get the count of handled interactions per day. + * + * @param ctx the context of the request + */ public void countDay(Context ctx) { var stats = metrics().service().day(offset(ctx, MAX_DAY_OFFSET), count(ctx, MAX_DAYS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -46,6 +65,11 @@ public void countDay(Context ctx) { } } + /** + * Handles the request to get the count of handled interactions per week. + * + * @param ctx the context of the request + */ public void countWeek(Context ctx) { var stats = metrics().service().week(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); if ("application/json".equals(ctx.header("Accept"))) { @@ -55,6 +79,11 @@ public void countWeek(Context ctx) { } } + /** + * Handles the request to get the count of handled interactions per month. + * + * @param ctx the context of the request + */ public void countMonth(Context ctx) { var stats = metrics().service().month(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -64,6 +93,9 @@ public void countMonth(Context ctx) { } } + /** + * Builds the routes for the service metrics. + */ @Override public void buildRoutes() { path("service", () -> path("count", () -> { diff --git a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Users.java b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Users.java index ffbad85df..414e97c06 100644 --- a/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Users.java +++ b/src/main/java/de/chojo/repbot/web/routes/v1/metrics/Users.java @@ -19,11 +19,25 @@ import static io.javalin.apibuilder.ApiBuilder.get; import static io.javalin.apibuilder.ApiBuilder.path; +/** + * Class for handling user metrics routes. + */ public class Users extends MetricsHolder { + /** + * Constructs a new Users instance. + * + * @param metrics the metrics provider + * @param cache the metric cache + */ public Users(Metrics metrics, MetricCache cache) { super(cache, metrics); } + /** + * Handles the active week user metrics request. + * + * @param ctx the context of the request + */ public void activeWeek(Context ctx) { var stats = metrics().users().week(offset(ctx, MAX_WEEK_OFFSET), count(ctx, MAX_WEEKS)); if ("application/json".equalsIgnoreCase(ctx.header("Accept"))) { @@ -33,6 +47,11 @@ public void activeWeek(Context ctx) { } } + /** + * Handles the active month user metrics request. + * + * @param ctx the context of the request + */ public void activeMonth(Context ctx) { var stats = metrics().users().month(offset(ctx, MAX_MONTH_OFFSET), count(ctx, MAX_MONTH)); if ("application/json".equals(ctx.header("Accept"))) { @@ -42,6 +61,9 @@ public void activeMonth(Context ctx) { } } + /** + * Builds the routes for user metrics. + */ @Override public void buildRoutes() { path("users", () -> path("active", () -> {