Skip to content

Commit ece6dbf

Browse files
committed
Made the methods private in auditcommand and extracted them into moderationutils
1 parent 4b9b662 commit ece6dbf

3 files changed

Lines changed: 99 additions & 71 deletions

File tree

application/src/main/java/org/togetherjava/tjbot/features/moderation/ModerationUtils.java

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.togetherjava.tjbot.features.moderation;
22

33
import net.dv8tion.jda.api.EmbedBuilder;
4+
import net.dv8tion.jda.api.JDA;
45
import net.dv8tion.jda.api.Permission;
56
import net.dv8tion.jda.api.entities.Guild;
67
import net.dv8tion.jda.api.entities.IPermissionHolder;
@@ -25,11 +26,17 @@
2526

2627
import java.awt.Color;
2728
import java.time.Instant;
29+
import java.time.ZoneOffset;
2830
import java.time.temporal.ChronoUnit;
2931
import java.time.temporal.TemporalUnit;
32+
import java.util.ArrayList;
33+
import java.util.Collection;
34+
import java.util.List;
35+
import java.util.Map;
3036
import java.util.Optional;
3137
import java.util.function.Predicate;
3238
import java.util.regex.Pattern;
39+
import java.util.stream.Collectors;
3340

3441
/**
3542
* Utility class offering helpers revolving around user moderation, such as banning or kicking.
@@ -273,7 +280,7 @@ static boolean handleHasAuthorPermissions(String actionVerb, Permission permissi
273280
* Creates a message to be displayed as response to a moderation action.
274281
* <p>
275282
* Essentially, it informs others about the action, such as "John banned Bob for playing with
276-
* the fire.".
283+
* the fire".
277284
*
278285
* @param author the author executing the action
279286
* @param action the action that is executed
@@ -442,4 +449,84 @@ static RestAction<Boolean> sendModActionDm(RestAction<EmbedBuilder> embedBuilder
442449
*/
443450
record TemporaryData(Instant expiresAt, String duration) {
444451
}
452+
453+
/**
454+
* Splits a list of moderation records into discrete pages capped at 10 items each.
455+
*
456+
* @param actions the list of chronological actions against a target
457+
* @return a list of sub-lists where each sub-list contains a maximum of 10 items
458+
*/
459+
public static List<List<ActionRecord>> groupActionsByPages(List<ActionRecord> actions) {
460+
List<List<ActionRecord>> groupedActions = new ArrayList<>();
461+
final int maxPageLength = 10;
462+
463+
for (int i = 0; i < actions.size(); i++) {
464+
if (i % maxPageLength == 0) {
465+
groupedActions.add(new ArrayList<>(maxPageLength));
466+
}
467+
groupedActions.getLast().add(actions.get(i));
468+
}
469+
470+
return groupedActions;
471+
}
472+
473+
/**
474+
* Generates a structural text overview outlining the count total of each action type.
475+
*
476+
* @param actions a collection of history records
477+
* @return a formatted markdown description summary
478+
*/
479+
public static String createSummaryMessageDescription(Collection<ActionRecord> actions) {
480+
int actionAmount = actions.size();
481+
482+
String shortSummary = "There are **%s actions** against the user."
483+
.formatted(actionAmount == 0 ? "no" : actionAmount);
484+
485+
if (actionAmount == 0) {
486+
return shortSummary;
487+
}
488+
489+
Map<ModerationAction, Long> actionTypeToCount = actions.stream()
490+
.collect(Collectors.groupingBy(ActionRecord::actionType, Collectors.counting()));
491+
492+
String typeCountSummary = actionTypeToCount.entrySet()
493+
.stream()
494+
.filter(typeAndCount -> typeAndCount.getValue() > 0)
495+
.sorted(Map.Entry.<ModerationAction, Long>comparingByValue().reversed())
496+
.map(typeAndCount -> "- **%s**: %d".formatted(typeAndCount.getKey(),
497+
typeAndCount.getValue()))
498+
.collect(Collectors.joining("\n"));
499+
500+
return shortSummary + "\n" + typeCountSummary;
501+
}
502+
503+
/**
504+
* Converts an action record item asynchronously into a formatted embed data field.
505+
*
506+
* @param action the record data item
507+
* @param jda the active JDA instance used to resolve the moderator's handle
508+
* @return a field representation task mapping out the execution card detail
509+
*/
510+
public static RestAction<MessageEmbed.Field> actionToField(ActionRecord action, JDA jda) {
511+
return jda.retrieveUserById(action.authorId())
512+
.map(author -> author == null ? "(unknown user)" : author.getName())
513+
.map(authorText -> {
514+
String expiresAtFormatted = action.actionExpiresAt() == null ? ""
515+
: "\nTemporary action, expires at: " + net.dv8tion.jda.api.utils.TimeUtil
516+
.getDateTimeString(action.actionExpiresAt().atOffset(ZoneOffset.UTC));
517+
518+
String fieldName = "%s by %s".formatted(action.actionType().name(), authorText);
519+
String fieldDescription =
520+
"""
521+
%s
522+
Issued at: %s%s
523+
""".formatted(action.reason(),
524+
net.dv8tion.jda.api.utils.TimeUtil
525+
.getDateTimeString(action.issuedAt().atOffset(ZoneOffset.UTC)),
526+
expiresAtFormatted);
527+
528+
return new MessageEmbed.Field(fieldName, fieldDescription, false);
529+
});
530+
}
531+
445532
}

application/src/main/java/org/togetherjava/tjbot/features/moderation/ReportCommand.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.togetherjava.tjbot.features.CommandVisibility;
2828
import org.togetherjava.tjbot.features.MessageContextCommand;
2929
import org.togetherjava.tjbot.features.componentids.Lifespan;
30-
import org.togetherjava.tjbot.features.moderation.audit.AuditCommand;
3130
import org.togetherjava.tjbot.features.utils.MessageUtils;
3231

3332
import java.awt.Color;
@@ -263,9 +262,9 @@ public void onButtonClick(ButtonInteractionEvent event, List<String> args) {
263262
new EmbedBuilder().setTitle("Audit log of **%s**".formatted(user.getName()))
264263
.setAuthor(user.getName(), null, user.getEffectiveAvatarUrl())
265264
.setColor(Color.BLACK)
266-
.setDescription(AuditCommand.createSummaryMessageDescription(actions));
265+
.setDescription(ModerationUtils.createSummaryMessageDescription(actions));
267266

268-
List<List<ActionRecord>> pages = AuditCommand.groupActionsByPages(actions);
267+
List<List<ActionRecord>> pages = ModerationUtils.groupActionsByPages(actions);
269268

270269
if (pages.isEmpty()) {
271270
event.getHook().sendMessageEmbeds(auditEmbed.build()).queue();
@@ -275,7 +274,7 @@ public void onButtonClick(ButtonInteractionEvent event, List<String> args) {
275274
List<net.dv8tion.jda.api.requests.RestAction<MessageEmbed.Field>> fieldTasks =
276275
pages.getLast()
277276
.stream()
278-
.map(action -> AuditCommand.actionToField(action, event.getJDA()))
277+
.map(action -> ModerationUtils.actionToField(action, event.getJDA()))
279278
.toList();
280279

281280
net.dv8tion.jda.api.requests.RestAction.allOf(fieldTasks).queue(fields -> {

application/src/main/java/org/togetherjava/tjbot/features/moderation/audit/AuditCommand.java

Lines changed: 8 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import net.dv8tion.jda.api.interactions.commands.OptionType;
1414
import net.dv8tion.jda.api.interactions.components.buttons.Button;
1515
import net.dv8tion.jda.api.requests.RestAction;
16-
import net.dv8tion.jda.api.utils.TimeUtil;
1716
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
1817
import net.dv8tion.jda.api.utils.messages.MessageEditBuilder;
1918
import net.dv8tion.jda.api.utils.messages.MessageRequest;
@@ -22,21 +21,16 @@
2221
import org.togetherjava.tjbot.features.CommandVisibility;
2322
import org.togetherjava.tjbot.features.SlashCommandAdapter;
2423
import org.togetherjava.tjbot.features.moderation.ActionRecord;
25-
import org.togetherjava.tjbot.features.moderation.ModerationAction;
2624
import org.togetherjava.tjbot.features.moderation.ModerationActionsStore;
2725
import org.togetherjava.tjbot.features.moderation.ModerationUtils;
2826

2927
import javax.annotation.Nullable;
3028

31-
import java.time.Instant;
32-
import java.time.ZoneOffset;
3329
import java.util.ArrayList;
3430
import java.util.Collection;
3531
import java.util.List;
36-
import java.util.Map;
3732
import java.util.Objects;
3833
import java.util.function.Supplier;
39-
import java.util.stream.Collectors;
4034

4135
/**
4236
* This command lists all moderation actions that have been taken against a given user, for example
@@ -49,7 +43,6 @@ public final class AuditCommand extends SlashCommandAdapter {
4943
private static final String TARGET_OPTION = "user";
5044
private static final String COMMAND_NAME = "audit";
5145
private static final String ACTION_VERB = "audit";
52-
private static final int MAX_PAGE_LENGTH = 10;
5346
private static final String PREVIOUS_BUTTON_LABEL = "⬅";
5447
private static final String NEXT_BUTTON_LABEL = "➡";
5548
private final ModerationActionsStore actionsStore;
@@ -101,8 +94,8 @@ private boolean handleChecks(Member bot, Member author, @Nullable Member target,
10194

10295
/**
10396
* @param pageNumber page number to display when actions are divided into pages and each page
104-
* can contain {@link AuditCommand#MAX_PAGE_LENGTH} actions, {@code -1} encodes the last
105-
* page
97+
* can contain {@link ModerationUtils#groupActionsByPages(List)} actions, {@code -1}
98+
* encodes the last page
10699
*/
107100
private <R extends MessageRequest<R>> RestAction<R> auditUser(
108101
Supplier<R> messageBuilderSupplier, long guildId, long targetId, long callerId,
@@ -126,53 +119,20 @@ private <R extends MessageRequest<R>> RestAction<R> auditUser(
126119
pageNumberInLimits, totalPages, guildId, targetId, callerId));
127120
}
128121

129-
public static List<List<ActionRecord>> groupActionsByPages(List<ActionRecord> actions) {
130-
List<List<ActionRecord>> groupedActions = new ArrayList<>();
131-
for (int i = 0; i < actions.size(); i++) {
132-
if (i % AuditCommand.MAX_PAGE_LENGTH == 0) {
133-
groupedActions.add(new ArrayList<>(AuditCommand.MAX_PAGE_LENGTH));
134-
}
135-
136-
groupedActions.getLast().add(actions.get(i));
137-
}
138-
139-
return groupedActions;
122+
private static List<List<ActionRecord>> groupActionsByPages(List<ActionRecord> actions) {
123+
return ModerationUtils.groupActionsByPages(actions);
140124
}
141125

142126
private static EmbedBuilder createSummaryEmbed(User user, Collection<ActionRecord> actions) {
143127
String avatarOrDefaultUrl = user.getEffectiveAvatarUrl();
144128

145129
return new EmbedBuilder().setTitle("Audit log of **%s**".formatted(user.getName()))
146130
.setAuthor(user.getName(), null, avatarOrDefaultUrl)
147-
.setDescription(createSummaryMessageDescription(actions))
131+
.setDescription(ModerationUtils.createSummaryMessageDescription(actions)) // Redirected
132+
// here
148133
.setColor(ModerationUtils.AMBIENT_COLOR);
149134
}
150135

151-
public static String createSummaryMessageDescription(Collection<ActionRecord> actions) {
152-
int actionAmount = actions.size();
153-
154-
String shortSummary = "There are **%s actions** against the user."
155-
.formatted(actionAmount == 0 ? "no" : actionAmount);
156-
157-
if (actionAmount == 0) {
158-
return shortSummary;
159-
}
160-
161-
// Summary of all actions with their count, like "- Warn: 5", descending
162-
Map<ModerationAction, Long> actionTypeToCount = actions.stream()
163-
.collect(Collectors.groupingBy(ActionRecord::actionType, Collectors.counting()));
164-
165-
String typeCountSummary = actionTypeToCount.entrySet()
166-
.stream()
167-
.filter(typeAndCount -> typeAndCount.getValue() > 0)
168-
.sorted(Map.Entry.<ModerationAction, Long>comparingByValue().reversed())
169-
.map(typeAndCount -> "- **%s**: %d".formatted(typeAndCount.getKey(),
170-
typeAndCount.getValue()))
171-
.collect(Collectors.joining("\n"));
172-
173-
return shortSummary + "\n" + typeCountSummary;
174-
}
175-
176136
private RestAction<EmbedBuilder> attachEmbedFields(EmbedBuilder auditEmbed,
177137
List<? extends List<ActionRecord>> groupedActions, int pageNumber, int totalPages,
178138
JDA jda) {
@@ -192,26 +152,8 @@ private RestAction<EmbedBuilder> attachEmbedFields(EmbedBuilder auditEmbed,
192152
});
193153
}
194154

195-
public static RestAction<MessageEmbed.Field> actionToField(ActionRecord action, JDA jda) {
196-
return jda.retrieveUserById(action.authorId())
197-
.map(author -> author == null ? "(unknown user)" : author.getName())
198-
.map(authorText -> {
199-
String expiresAtFormatted = action.actionExpiresAt() == null ? ""
200-
: "\nTemporary action, expires at: " + formatTime(action.actionExpiresAt());
201-
202-
String fieldName = "%s by %s".formatted(action.actionType().name(), authorText);
203-
String fieldDescription = """
204-
%s
205-
Issued at: %s%s
206-
""".formatted(action.reason(), formatTime(action.issuedAt()),
207-
expiresAtFormatted);
208-
209-
return new MessageEmbed.Field(fieldName, fieldDescription, false);
210-
});
211-
}
212-
213-
private static String formatTime(Instant when) {
214-
return TimeUtil.getDateTimeString(when.atOffset(ZoneOffset.UTC));
155+
private static RestAction<MessageEmbed.Field> actionToField(ActionRecord action, JDA jda) {
156+
return ModerationUtils.actionToField(action, jda);
215157
}
216158

217159
private <R extends MessageRequest<R>> R attachPageTurnButtons(

0 commit comments

Comments
 (0)