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/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/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..42fbfc147 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,31 +49,43 @@ 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; } /** - * Get members which have written in the channel of the message. - *

- * 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 + * Gets the context of members who have written in the channel of the specified message. * - * @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 +107,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 +126,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 +143,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 +166,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 +182,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 +200,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 +231,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/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/empty/EmptyAnalyzerResult.java b/src/main/java/de/chojo/repbot/analyzer/results/empty/EmptyAnalyzerResult.java index 7b2a6c144..aede79a1f 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,38 @@ import javax.annotation.Nullable; +/** + * Represents an empty analyzer result with a match and a reason. + */ 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/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/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..03deeba2c 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,16 @@ 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 { + /** + * 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..b88a3f4e4 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,18 @@ 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 { + /** + * 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/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/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/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/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/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/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/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/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..288752947 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,16 @@ 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 { + /** + * 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/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..6278b9e7c 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,17 @@ 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 { + /** + * 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 +52,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/prune/Prune.java b/src/main/java/de/chojo/repbot/commands/prune/Prune.java index a65d1a68a..f1db36871 100644 --- a/src/main/java/de/chojo/repbot/commands/prune/Prune.java +++ b/src/main/java/de/chojo/repbot/commands/prune/Prune.java @@ -14,8 +14,16 @@ import de.chojo.repbot.service.GdprService; import net.dv8tion.jda.api.Permission; +/** + * Represents the Prune command which allows pruning of users or guilds. + */ public class Prune extends SlashCommand { + /** + * Constructs a Prune command with the specified GDPR service. + * + * @param service the GDPR service to handle pruning operations + */ public Prune(GdprService service) { super(Slash.of("prune", "command.prune.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/prune/handler/Guild.java b/src/main/java/de/chojo/repbot/commands/prune/handler/Guild.java index 431f3e8d0..8e9091c45 100644 --- a/src/main/java/de/chojo/repbot/commands/prune/handler/Guild.java +++ b/src/main/java/de/chojo/repbot/commands/prune/handler/Guild.java @@ -14,14 +14,28 @@ import static org.slf4j.LoggerFactory.getLogger; +/** + * Handles the guild prune slash command. + */ public class Guild implements SlashHandler { private static final Logger log = getLogger(Guild.class); private final GdprService service; + /** + * Constructs a new Guild instance. + * + * @param service the GdprService instance + */ public Guild(GdprService service) { this.service = service; } + /** + * Handles the slash command interaction event. + * + * @param event the SlashCommandInteractionEvent + * @param context the EventContext + */ @Override public void onSlashCommand(SlashCommandInteractionEvent event, EventContext context) { event.reply(context.localize("command.prune.guild.message.started")).queue(); diff --git a/src/main/java/de/chojo/repbot/commands/reactions/Reactions.java b/src/main/java/de/chojo/repbot/commands/reactions/Reactions.java index f2767a520..97e762ab7 100644 --- a/src/main/java/de/chojo/repbot/commands/reactions/Reactions.java +++ b/src/main/java/de/chojo/repbot/commands/reactions/Reactions.java @@ -15,7 +15,15 @@ import de.chojo.repbot.commands.reactions.handler.Remove; import de.chojo.repbot.dao.provider.Guilds; +/** + * Represents the slash command for managing reactions in a guild. + */ public class Reactions extends SlashCommand { + /** + * Constructs a Reactions command with the specified guilds provider. + * + * @param guilds the guilds provider + */ public Reactions(Guilds guilds) { super(Slash.of("reactions", "command.reactions.description") .guildOnly() diff --git a/src/main/java/de/chojo/repbot/commands/reactions/handler/Add.java b/src/main/java/de/chojo/repbot/commands/reactions/handler/Add.java index 423726120..782b748aa 100644 --- a/src/main/java/de/chojo/repbot/commands/reactions/handler/Add.java +++ b/src/main/java/de/chojo/repbot/commands/reactions/handler/Add.java @@ -16,13 +16,27 @@ import static de.chojo.repbot.commands.reactions.util.EmojiCheck.checkEmoji; +/** + * Handler for the "add reaction" slash command, which adds a reaction to a message. + */ 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 emote = event.getOption("emote").getAsString(); @@ -31,6 +45,14 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont handleAddCheckResult(event.getGuild(), context, message, emote); } + /** + * Handles the result of the emoji check and adds the reaction accordingly. + * + * @param guild the guild where the command was executed + * @param context the event context + * @param message the message to add the reaction to + * @param emote the emote to add as a reaction + */ private void handleAddCheckResult(Guild guild, EventContext context, Message message, String emote) { var reactions = guilds.guild(guild).settings().thanking().reactions(); var result = checkEmoji(message, emote); diff --git a/src/main/java/de/chojo/repbot/commands/reactions/handler/Info.java b/src/main/java/de/chojo/repbot/commands/reactions/handler/Info.java index d66f399cf..65d5dfebc 100644 --- a/src/main/java/de/chojo/repbot/commands/reactions/handler/Info.java +++ b/src/main/java/de/chojo/repbot/commands/reactions/handler/Info.java @@ -13,18 +13,39 @@ import net.dv8tion.jda.api.entities.MessageEmbed; import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +/** + * Handler for the slash command that provides information about reactions. + */ 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(getInfoEmbed(guilds.guild(event.getGuild()).settings(), context)).queue(); } + /** + * Creates an information embed about the reactions. + * + * @param settings the guild settings + * @param context the event context + * @return a MessageEmbed containing the information + */ private MessageEmbed getInfoEmbed(Settings settings, EventContext context) { var reactions = settings.thanking().reactions(); var mainEmote = reactions.reactionMention(); @@ -36,5 +57,4 @@ private MessageEmbed getInfoEmbed(Settings settings, EventContext context) { .addField("command.reactions.info.message.additional", emotes, true) .build(); } - } diff --git a/src/main/java/de/chojo/repbot/commands/reactions/handler/Main.java b/src/main/java/de/chojo/repbot/commands/reactions/handler/Main.java index 02a185ecb..36b17050b 100644 --- a/src/main/java/de/chojo/repbot/commands/reactions/handler/Main.java +++ b/src/main/java/de/chojo/repbot/commands/reactions/handler/Main.java @@ -16,13 +16,27 @@ import static de.chojo.repbot.commands.reactions.util.EmojiCheck.checkEmoji; +/** + * Handler for the main slash command related to reactions. + */ public class Main implements SlashHandler { private final Guilds guilds; + /** + * Constructs a new Main handler. + * + * @param guilds the Guilds provider + */ public Main(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 emote = event.getOption("emote").getAsString(); @@ -31,6 +45,14 @@ public void onSlashCommand(SlashCommandInteractionEvent event, EventContext cont handleSetCheckResult(event.getGuild(), context, message, emote); } + /** + * Handles the result of the emoji check and updates the message accordingly. + * + * @param guild the Guild where the command was executed + * @param context the EventContext + * @param message the Message to update + * @param emote the emote to check + */ private void handleSetCheckResult(Guild guild, EventContext context, Message message, String emote) { var reactions = guilds.guild(guild).settings().thanking().reactions(); var result = checkEmoji(message, emote); diff --git a/src/main/java/de/chojo/repbot/commands/reactions/handler/Remove.java b/src/main/java/de/chojo/repbot/commands/reactions/handler/Remove.java index 2709fec95..25034bb01 100644 --- a/src/main/java/de/chojo/repbot/commands/reactions/handler/Remove.java +++ b/src/main/java/de/chojo/repbot/commands/reactions/handler/Remove.java @@ -14,15 +14,29 @@ import java.util.regex.Pattern; +/** + * Handles the removal of reactions in a guild. + */ public class Remove implements SlashHandler { private static final Pattern EMOTE_PATTERN = Pattern.compile("\\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/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/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/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 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/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/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/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/config/ConfigFile.java b/src/main/java/de/chojo/repbot/config/ConfigFile.java index 8ed1e64c2..1b3467cfc 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,101 @@ public class ConfigFile { private SelfCleanup selfcleanup = new SelfCleanup(); private Cleanup cleanup = new Cleanup(); + /** + * 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..6abaa2d5e 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,38 @@ public class AnalyzerSettings { private int latestMaxHours = 12; private float minFuzzyScore = 0.9f; + /** + * 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..9bc4cea45 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,38 @@ */ 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"; + /** + * 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/BaseSettings.java b/src/main/java/de/chojo/repbot/config/elements/BaseSettings.java index f2011f45c..6ca1c7116 100644 --- a/src/main/java/de/chojo/repbot/config/elements/BaseSettings.java +++ b/src/main/java/de/chojo/repbot/config/elements/BaseSettings.java @@ -14,14 +14,30 @@ public class BaseSettings { private List botOwner = new ArrayList<>(); private long botGuild = 0L; + /** + * 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..40be76fde 100644 --- a/src/main/java/de/chojo/repbot/config/elements/Botlist.java +++ b/src/main/java/de/chojo/repbot/config/elements/Botlist.java @@ -15,26 +15,57 @@ public class Botlist { private BotListConfig discordBotlistCom = new BotListConfig("discordbotlist.com", "", "", 450100127256936458L, "", ""); private BotListConfig botListMe = new BotListConfig("discordbotlist.com", "", "", 698637043240009738L, "", ""); + /** + * 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 +76,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/Database.java b/src/main/java/de/chojo/repbot/config/elements/Database.java index b53c141a6..60d4c6a87 100644 --- a/src/main/java/de/chojo/repbot/config/elements/Database.java +++ b/src/main/java/de/chojo/repbot/config/elements/Database.java @@ -5,7 +5,6 @@ */ package de.chojo.repbot.config.elements; - @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) public class Database { private String host = "localhost"; @@ -16,30 +15,65 @@ public class Database { private String password = "pw"; private int poolSize = 5; + /** + * 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..fc016ee69 100644 --- a/src/main/java/de/chojo/repbot/config/elements/Links.java +++ b/src/main/java/de/chojo/repbot/config/elements/Links.java @@ -13,22 +13,47 @@ public class Links { private String website = "https://rainbowdashlabs.github.io/reputation-bot/"; private String faq = "https://rainbowdashlabs.github.io/reputation-bot/faq"; + /** + * 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..ac6d8ffbe 100644 --- a/src/main/java/de/chojo/repbot/config/elements/MagicImage.java +++ b/src/main/java/de/chojo/repbot/config/elements/MagicImage.java @@ -5,7 +5,6 @@ */ package de.chojo.repbot.config.elements; - @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal", "CanBeFinal"}) public class MagicImage { private String magicImageLink = ""; @@ -13,18 +12,38 @@ public class MagicImage { private int magicImageCooldown = 30; private int magicImageDeleteSchedule = 60; + /** + * 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..bffeb4c4f 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,89 @@ public class PresenceSettings { Presence.of(Activity.ActivityType.LISTENING, "%analyzed_messages% messages during the last hour!") ); + /** + * 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/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/dao/access/Cleanup.java b/src/main/java/de/chojo/repbot/dao/access/Cleanup.java index 9b6d7d917..c8e0384e5 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,16 @@ import java.util.List; +/** + * Class responsible for handling cleanup operations in the database. + */ public class 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/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/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/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/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/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/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/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/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/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/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/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/builder/LabeledCountStatisticBuilder.java b/src/main/java/de/chojo/repbot/dao/snapshots/statistics/builder/LabeledCountStatisticBuilder.java index 0c79e46bc..a963e4114 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,29 @@ import java.util.List; import java.util.Map; +/** + * Builder class for creating LabeledCountStatistic instances. + */ public class LabeledCountStatisticBuilder { private final Map> stats = new LinkedHashMap<>(); + /** + * 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/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/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/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/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/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/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/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..1d0f1d96c 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,32 @@ * * 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 { 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");