From 246b3e3430bef117e1d48f56cb72c382dff72ed6 Mon Sep 17 00:00:00 2001 From: Zabuzard Date: Mon, 18 Sep 2023 11:10:20 +0200 Subject: [PATCH] added helper prune config --- application/config.json.template | 7 ++++ .../org/togetherjava/tjbot/config/Config.java | 15 ++++++++- .../tjbot/config/HelperPruneConfig.java | 19 +++++++++++ .../features/help/AutoPruneHelperRoutine.java | 32 ++++++++++++------- 4 files changed, 60 insertions(+), 13 deletions(-) create mode 100644 application/src/main/java/org/togetherjava/tjbot/config/HelperPruneConfig.java diff --git a/application/config.json.template b/application/config.json.template index 80585e39b4..5391037110 100644 --- a/application/config.json.template +++ b/application/config.json.template @@ -94,5 +94,12 @@ "baseUrl": "", "rateLimitWindowSeconds": 10, "rateLimitRequestsInWindow": 3 + }, + "helperPruneConfig": { + "roleFullLimit": 100, + "roleFullThreshold": 95, + "pruneMemberAmount": 7, + "inactivateAfterDays": 90, + "recentlyJoinedDays": 4 } } diff --git a/application/src/main/java/org/togetherjava/tjbot/config/Config.java b/application/src/main/java/org/togetherjava/tjbot/config/Config.java index f16aed61b4..4697573b06 100644 --- a/application/src/main/java/org/togetherjava/tjbot/config/Config.java +++ b/application/src/main/java/org/togetherjava/tjbot/config/Config.java @@ -39,6 +39,7 @@ public final class Config { private final String openaiApiKey; private final String sourceCodeBaseUrl; private final JShellConfig jshell; + private final HelperPruneConfig helperPruneConfig; @SuppressWarnings("ConstructorWithTooManyParameters") @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) @@ -76,7 +77,9 @@ private Config(@JsonProperty(value = "token", required = true) String token, required = true) String logErrorChannelWebhook, @JsonProperty(value = "openaiApiKey", required = true) String openaiApiKey, @JsonProperty(value = "sourceCodeBaseUrl", required = true) String sourceCodeBaseUrl, - @JsonProperty(value = "jshell", required = true) JShellConfig jshell) { + @JsonProperty(value = "jshell", required = true) JShellConfig jshell, + @JsonProperty(value = "helperPruneConfig", + required = true) HelperPruneConfig helperPruneConfig) { this.token = Objects.requireNonNull(token); this.gistApiKey = Objects.requireNonNull(gistApiKey); this.databasePath = Objects.requireNonNull(databasePath); @@ -102,6 +105,7 @@ private Config(@JsonProperty(value = "token", required = true) String token, this.openaiApiKey = Objects.requireNonNull(openaiApiKey); this.sourceCodeBaseUrl = Objects.requireNonNull(sourceCodeBaseUrl); this.jshell = Objects.requireNonNull(jshell); + this.helperPruneConfig = Objects.requireNonNull(helperPruneConfig); } /** @@ -342,4 +346,13 @@ public String getSourceCodeBaseUrl() { public JShellConfig getJshell() { return jshell; } + + /** + * Gets the config for automatic pruning of helper roles. + * + * @return the configuration + */ + public HelperPruneConfig getHelperPruneConfig() { + return helperPruneConfig; + } } diff --git a/application/src/main/java/org/togetherjava/tjbot/config/HelperPruneConfig.java b/application/src/main/java/org/togetherjava/tjbot/config/HelperPruneConfig.java new file mode 100644 index 0000000000..6f451b491f --- /dev/null +++ b/application/src/main/java/org/togetherjava/tjbot/config/HelperPruneConfig.java @@ -0,0 +1,19 @@ +package org.togetherjava.tjbot.config; + + +/** + * Config for automatic pruning of helper roles, see + * {@link org.togetherjava.tjbot.features.help.AutoPruneHelperRoutine}. + * + * @param roleFullLimit if a helper role contains that many users, it is considered full and pruning + * must occur + * @param roleFullThreshold if a helper role contains that many users, pruning will start to occur + * to prevent reaching the limit + * @param pruneMemberAmount amount of users to remove from helper roles during a prune + * @param inactivateAfterDays after how many days of inactivity a user is eligible for pruning + * @param recentlyJoinedDays if a user is with the server for just this amount of days, they are + * protected from pruning + */ +public record HelperPruneConfig(int roleFullLimit, int roleFullThreshold, int pruneMemberAmount, + int inactivateAfterDays, int recentlyJoinedDays) { +} diff --git a/application/src/main/java/org/togetherjava/tjbot/features/help/AutoPruneHelperRoutine.java b/application/src/main/java/org/togetherjava/tjbot/features/help/AutoPruneHelperRoutine.java index 183dd2ab79..9fcd05e4ef 100644 --- a/application/src/main/java/org/togetherjava/tjbot/features/help/AutoPruneHelperRoutine.java +++ b/application/src/main/java/org/togetherjava/tjbot/features/help/AutoPruneHelperRoutine.java @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory; import org.togetherjava.tjbot.config.Config; +import org.togetherjava.tjbot.config.HelperPruneConfig; import org.togetherjava.tjbot.db.Database; import org.togetherjava.tjbot.features.Routine; import org.togetherjava.tjbot.features.moderation.audit.ModAuditLogWriter; @@ -31,11 +32,11 @@ public final class AutoPruneHelperRoutine implements Routine { private static final Logger logger = LoggerFactory.getLogger(AutoPruneHelperRoutine.class); - private static final int ROLE_FULL_LIMIT = 100; - private static final int ROLE_FULL_THRESHOLD = 95; - private static final int PRUNE_MEMBER_AMOUNT = 7; - private static final Period INACTIVE_AFTER = Period.ofDays(90); - private static final int RECENTLY_JOINED_DAYS = 4; + private final int roleFullLimit; + private final int roleFullThreshold; + private final int pruneMemberAmount; + private final Period inactiveAfter; + private final int recentlyJoinedDays; private final HelpSystemHelper helper; private final ModAuditLogWriter modAuditLogWriter; @@ -56,6 +57,13 @@ public AutoPruneHelperRoutine(Config config, HelpSystemHelper helper, this.helper = helper; this.modAuditLogWriter = modAuditLogWriter; this.database = database; + + HelperPruneConfig helperPruneConfig = config.getHelperPruneConfig(); + roleFullLimit = helperPruneConfig.roleFullLimit(); + roleFullThreshold = helperPruneConfig.roleFullThreshold(); + pruneMemberAmount = helperPruneConfig.pruneMemberAmount(); + inactiveAfter = Period.ofDays(helperPruneConfig.inactivateAfterDays()); + recentlyJoinedDays = helperPruneConfig.recentlyJoinedDays(); } @Override @@ -93,7 +101,7 @@ private void pruneRoleIfFull(Role role, ForumChannel helpForum, Instant when) { } private boolean isRoleFull(Collection members) { - return members.size() >= ROLE_FULL_THRESHOLD; + return members.size() >= roleFullThreshold; } private void pruneRole(Role role, List members, ForumChannel helpForum, @@ -103,18 +111,18 @@ private void pruneRole(Role role, List members, ForumChannel h List membersToPrune = membersShuffled.stream() .filter(member -> isMemberInactive(member, when)) - .limit(PRUNE_MEMBER_AMOUNT) + .limit(pruneMemberAmount) .toList(); - if (membersToPrune.size() < PRUNE_MEMBER_AMOUNT) { + if (membersToPrune.size() < pruneMemberAmount) { warnModsAbout( "Attempting to prune helpers from role **%s** (%d members), but only found %d inactive users. That is less than expected, the category might eventually grow beyond the limit." .formatted(role.getName(), members.size(), membersToPrune.size()), role.getGuild()); } - if (members.size() - membersToPrune.size() >= ROLE_FULL_LIMIT) { + if (members.size() - membersToPrune.size() >= roleFullLimit) { warnModsAbout( "The helper role **%s** went beyond its member limit (%d), despite automatic pruning. It will not function correctly anymore. Please manually prune some users." - .formatted(role.getName(), ROLE_FULL_LIMIT), + .formatted(role.getName(), roleFullLimit), role.getGuild()); } @@ -126,14 +134,14 @@ private void pruneRole(Role role, List members, ForumChannel h private boolean isMemberInactive(Member member, Instant when) { if (member.hasTimeJoined()) { Instant memberJoined = member.getTimeJoined().toInstant(); - if (Duration.between(memberJoined, when).toDays() <= RECENTLY_JOINED_DAYS) { + if (Duration.between(memberJoined, when).toDays() <= recentlyJoinedDays) { // New users are protected from purging to not immediately kick them out of the role // again return false; } } - Instant latestActiveMoment = when.minus(INACTIVE_AFTER); + Instant latestActiveMoment = when.minus(inactiveAfter); // Has no recent help message return database.read(context -> context.fetchCount(HELP_CHANNEL_MESSAGES,