Skip to content

Commit 69d4f78

Browse files
authored
added helper prune config (#889)
1 parent e9a7f32 commit 69d4f78

File tree

4 files changed

+60
-13
lines changed

4 files changed

+60
-13
lines changed

application/config.json.template

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,12 @@
9494
"baseUrl": "<put_jshell_rest_api_url_here>",
9595
"rateLimitWindowSeconds": 10,
9696
"rateLimitRequestsInWindow": 3
97+
},
98+
"helperPruneConfig": {
99+
"roleFullLimit": 100,
100+
"roleFullThreshold": 95,
101+
"pruneMemberAmount": 7,
102+
"inactivateAfterDays": 90,
103+
"recentlyJoinedDays": 4
97104
}
98105
}

application/src/main/java/org/togetherjava/tjbot/config/Config.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public final class Config {
3939
private final String openaiApiKey;
4040
private final String sourceCodeBaseUrl;
4141
private final JShellConfig jshell;
42+
private final HelperPruneConfig helperPruneConfig;
4243

4344
@SuppressWarnings("ConstructorWithTooManyParameters")
4445
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
@@ -76,7 +77,9 @@ private Config(@JsonProperty(value = "token", required = true) String token,
7677
required = true) String logErrorChannelWebhook,
7778
@JsonProperty(value = "openaiApiKey", required = true) String openaiApiKey,
7879
@JsonProperty(value = "sourceCodeBaseUrl", required = true) String sourceCodeBaseUrl,
79-
@JsonProperty(value = "jshell", required = true) JShellConfig jshell) {
80+
@JsonProperty(value = "jshell", required = true) JShellConfig jshell,
81+
@JsonProperty(value = "helperPruneConfig",
82+
required = true) HelperPruneConfig helperPruneConfig) {
8083
this.token = Objects.requireNonNull(token);
8184
this.gistApiKey = Objects.requireNonNull(gistApiKey);
8285
this.databasePath = Objects.requireNonNull(databasePath);
@@ -102,6 +105,7 @@ private Config(@JsonProperty(value = "token", required = true) String token,
102105
this.openaiApiKey = Objects.requireNonNull(openaiApiKey);
103106
this.sourceCodeBaseUrl = Objects.requireNonNull(sourceCodeBaseUrl);
104107
this.jshell = Objects.requireNonNull(jshell);
108+
this.helperPruneConfig = Objects.requireNonNull(helperPruneConfig);
105109
}
106110

107111
/**
@@ -342,4 +346,13 @@ public String getSourceCodeBaseUrl() {
342346
public JShellConfig getJshell() {
343347
return jshell;
344348
}
349+
350+
/**
351+
* Gets the config for automatic pruning of helper roles.
352+
*
353+
* @return the configuration
354+
*/
355+
public HelperPruneConfig getHelperPruneConfig() {
356+
return helperPruneConfig;
357+
}
345358
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.togetherjava.tjbot.config;
2+
3+
4+
/**
5+
* Config for automatic pruning of helper roles, see
6+
* {@link org.togetherjava.tjbot.features.help.AutoPruneHelperRoutine}.
7+
*
8+
* @param roleFullLimit if a helper role contains that many users, it is considered full and pruning
9+
* must occur
10+
* @param roleFullThreshold if a helper role contains that many users, pruning will start to occur
11+
* to prevent reaching the limit
12+
* @param pruneMemberAmount amount of users to remove from helper roles during a prune
13+
* @param inactivateAfterDays after how many days of inactivity a user is eligible for pruning
14+
* @param recentlyJoinedDays if a user is with the server for just this amount of days, they are
15+
* protected from pruning
16+
*/
17+
public record HelperPruneConfig(int roleFullLimit, int roleFullThreshold, int pruneMemberAmount,
18+
int inactivateAfterDays, int recentlyJoinedDays) {
19+
}

application/src/main/java/org/togetherjava/tjbot/features/help/AutoPruneHelperRoutine.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.slf4j.LoggerFactory;
1010

1111
import org.togetherjava.tjbot.config.Config;
12+
import org.togetherjava.tjbot.config.HelperPruneConfig;
1213
import org.togetherjava.tjbot.db.Database;
1314
import org.togetherjava.tjbot.features.Routine;
1415
import org.togetherjava.tjbot.features.moderation.audit.ModAuditLogWriter;
@@ -31,11 +32,11 @@
3132
public final class AutoPruneHelperRoutine implements Routine {
3233
private static final Logger logger = LoggerFactory.getLogger(AutoPruneHelperRoutine.class);
3334

34-
private static final int ROLE_FULL_LIMIT = 100;
35-
private static final int ROLE_FULL_THRESHOLD = 95;
36-
private static final int PRUNE_MEMBER_AMOUNT = 7;
37-
private static final Period INACTIVE_AFTER = Period.ofDays(90);
38-
private static final int RECENTLY_JOINED_DAYS = 4;
35+
private final int roleFullLimit;
36+
private final int roleFullThreshold;
37+
private final int pruneMemberAmount;
38+
private final Period inactiveAfter;
39+
private final int recentlyJoinedDays;
3940

4041
private final HelpSystemHelper helper;
4142
private final ModAuditLogWriter modAuditLogWriter;
@@ -56,6 +57,13 @@ public AutoPruneHelperRoutine(Config config, HelpSystemHelper helper,
5657
this.helper = helper;
5758
this.modAuditLogWriter = modAuditLogWriter;
5859
this.database = database;
60+
61+
HelperPruneConfig helperPruneConfig = config.getHelperPruneConfig();
62+
roleFullLimit = helperPruneConfig.roleFullLimit();
63+
roleFullThreshold = helperPruneConfig.roleFullThreshold();
64+
pruneMemberAmount = helperPruneConfig.pruneMemberAmount();
65+
inactiveAfter = Period.ofDays(helperPruneConfig.inactivateAfterDays());
66+
recentlyJoinedDays = helperPruneConfig.recentlyJoinedDays();
5967
}
6068

6169
@Override
@@ -93,7 +101,7 @@ private void pruneRoleIfFull(Role role, ForumChannel helpForum, Instant when) {
93101
}
94102

95103
private boolean isRoleFull(Collection<?> members) {
96-
return members.size() >= ROLE_FULL_THRESHOLD;
104+
return members.size() >= roleFullThreshold;
97105
}
98106

99107
private void pruneRole(Role role, List<? extends Member> members, ForumChannel helpForum,
@@ -103,18 +111,18 @@ private void pruneRole(Role role, List<? extends Member> members, ForumChannel h
103111

104112
List<Member> membersToPrune = membersShuffled.stream()
105113
.filter(member -> isMemberInactive(member, when))
106-
.limit(PRUNE_MEMBER_AMOUNT)
114+
.limit(pruneMemberAmount)
107115
.toList();
108-
if (membersToPrune.size() < PRUNE_MEMBER_AMOUNT) {
116+
if (membersToPrune.size() < pruneMemberAmount) {
109117
warnModsAbout(
110118
"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."
111119
.formatted(role.getName(), members.size(), membersToPrune.size()),
112120
role.getGuild());
113121
}
114-
if (members.size() - membersToPrune.size() >= ROLE_FULL_LIMIT) {
122+
if (members.size() - membersToPrune.size() >= roleFullLimit) {
115123
warnModsAbout(
116124
"The helper role **%s** went beyond its member limit (%d), despite automatic pruning. It will not function correctly anymore. Please manually prune some users."
117-
.formatted(role.getName(), ROLE_FULL_LIMIT),
125+
.formatted(role.getName(), roleFullLimit),
118126
role.getGuild());
119127
}
120128

@@ -126,14 +134,14 @@ private void pruneRole(Role role, List<? extends Member> members, ForumChannel h
126134
private boolean isMemberInactive(Member member, Instant when) {
127135
if (member.hasTimeJoined()) {
128136
Instant memberJoined = member.getTimeJoined().toInstant();
129-
if (Duration.between(memberJoined, when).toDays() <= RECENTLY_JOINED_DAYS) {
137+
if (Duration.between(memberJoined, when).toDays() <= recentlyJoinedDays) {
130138
// New users are protected from purging to not immediately kick them out of the role
131139
// again
132140
return false;
133141
}
134142
}
135143

136-
Instant latestActiveMoment = when.minus(INACTIVE_AFTER);
144+
Instant latestActiveMoment = when.minus(inactiveAfter);
137145

138146
// Has no recent help message
139147
return database.read(context -> context.fetchCount(HELP_CHANNEL_MESSAGES,

0 commit comments

Comments
 (0)