Skip to content

Commit

Permalink
added helper prune config (#889)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zabuzard authored Sep 18, 2023
1 parent e9a7f32 commit 69d4f78
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 13 deletions.
7 changes: 7 additions & 0 deletions application/config.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,12 @@
"baseUrl": "<put_jshell_rest_api_url_here>",
"rateLimitWindowSeconds": 10,
"rateLimitRequestsInWindow": 3
},
"helperPruneConfig": {
"roleFullLimit": 100,
"roleFullThreshold": 95,
"pruneMemberAmount": 7,
"inactivateAfterDays": 90,
"recentlyJoinedDays": 4
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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<? extends Member> members, ForumChannel helpForum,
Expand All @@ -103,18 +111,18 @@ private void pruneRole(Role role, List<? extends Member> members, ForumChannel h

List<Member> 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());
}

Expand All @@ -126,14 +134,14 @@ private void pruneRole(Role role, List<? extends Member> 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,
Expand Down

0 comments on commit 69d4f78

Please sign in to comment.