Skip to content

Commit cc4aa6e

Browse files
committed
allow exporting warns
1 parent f6aca25 commit cc4aa6e

File tree

7 files changed

+136
-8
lines changed

7 files changed

+136
-8
lines changed

src/main/java/net/javadiscord/javabot/api/routes/user_profile/UserProfileController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public ResponseEntity<UserProfileData> getUserProfile(
115115
data.setPreferences(preferences);
116116
// User Warns
117117
LocalDateTime cutoff = LocalDateTime.now().minusDays(botConfig.get(guild).getModerationConfig().getWarnTimeoutDays());
118-
data.setWarns(warnRepository.getWarnsByUserId(user.getIdLong(), cutoff));
118+
data.setWarns(warnRepository.getActiveWarnsByUserId(user.getIdLong(), cutoff));
119119
// Insert into cache
120120
getCache().put(new Pair<>(guild.getIdLong(), user.getIdLong()), data);
121121
}

src/main/java/net/javadiscord/javabot/systems/moderation/ModerationService.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ public boolean discardWarnById(long id, User clearedBy) {
144144
}
145145

146146
/**
147-
* Gets all warns based on the user id.
147+
* Gets warns based on the user id.
148148
*
149149
* @param userId The user's id.
150150
* @return A {@link List} with all warns.
@@ -153,7 +153,23 @@ public List<Warn> getWarns(long userId) {
153153
try {
154154
WarnRepository repo = warnRepository;
155155
LocalDateTime cutoff = LocalDateTime.now().minusDays(moderationConfig.getWarnTimeoutDays());
156-
return repo.getWarnsByUserId(userId, cutoff);
156+
return repo.getActiveWarnsByUserId(userId, cutoff);
157+
} catch (DataAccessException e) {
158+
ExceptionLogger.capture(e, getClass().getSimpleName());
159+
return List.of();
160+
}
161+
}
162+
163+
/**
164+
* Gets all warns based on the user id.
165+
*
166+
* @param userId The user's id.
167+
* @return A {@link List} with all warns.
168+
*/
169+
public List<Warn> getAllWarns(long userId) {
170+
try {
171+
WarnRepository repo = warnRepository;
172+
return repo.getAllWarnsByUserId(userId);
157173
} catch (DataAccessException e) {
158174
ExceptionLogger.capture(e, getClass().getSimpleName());
159175
return List.of();

src/main/java/net/javadiscord/javabot/systems/moderation/warn/WarnCommand.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ public class WarnCommand extends SlashCommand implements CommandModerationPermis
1515
* @param warnAddSubcommand /warn add
1616
* @param discardWarnByIdSubCommand /warn discard-by-id
1717
* @param discardAllWarnsSubcommand /warn discard-all
18+
* @param exportSubcommand /warn export
1819
*/
19-
public WarnCommand(WarnAddSubcommand warnAddSubcommand, DiscardWarnByIdSubCommand discardWarnByIdSubCommand, DiscardAllWarnsSubcommand discardAllWarnsSubcommand) {
20+
public WarnCommand(WarnAddSubcommand warnAddSubcommand, DiscardWarnByIdSubCommand discardWarnByIdSubCommand, DiscardAllWarnsSubcommand discardAllWarnsSubcommand, WarnExportSubcommand exportSubcommand) {
2021
setModerationSlashCommandData(Commands.slash("warn", "Administrative commands for managing user warns."));
21-
addSubcommands(warnAddSubcommand, discardWarnByIdSubCommand, discardAllWarnsSubcommand);
22+
addSubcommands(warnAddSubcommand, discardWarnByIdSubCommand, discardAllWarnsSubcommand, exportSubcommand);
2223
}
2324
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package net.javadiscord.javabot.systems.moderation.warn;
2+
3+
import xyz.dynxsty.dih4jda.interactions.commands.application.SlashCommand;
4+
import net.dv8tion.jda.api.EmbedBuilder;
5+
import net.dv8tion.jda.api.entities.User;
6+
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
7+
import net.dv8tion.jda.api.interactions.commands.OptionMapping;
8+
import net.dv8tion.jda.api.interactions.commands.OptionType;
9+
import net.dv8tion.jda.api.interactions.commands.build.OptionData;
10+
import net.dv8tion.jda.api.interactions.commands.build.SubcommandData;
11+
import net.dv8tion.jda.api.utils.FileUpload;
12+
import net.javadiscord.javabot.data.config.BotConfig;
13+
import net.javadiscord.javabot.systems.moderation.ModerationService;
14+
import net.javadiscord.javabot.systems.moderation.warn.dao.WarnRepository;
15+
import net.javadiscord.javabot.systems.moderation.warn.model.Warn;
16+
import net.javadiscord.javabot.systems.notification.NotificationService;
17+
import net.javadiscord.javabot.util.ExceptionLogger;
18+
import net.javadiscord.javabot.util.Responses;
19+
20+
import java.io.BufferedOutputStream;
21+
import java.io.IOException;
22+
import java.io.OutputStreamWriter;
23+
import java.io.PipedInputStream;
24+
import java.io.PipedOutputStream;
25+
import java.io.PrintWriter;
26+
import java.nio.charset.StandardCharsets;
27+
import java.util.Iterator;
28+
import java.util.List;
29+
import java.util.concurrent.ExecutorService;
30+
31+
import org.jetbrains.annotations.NotNull;
32+
33+
/**
34+
* <h3>This class represents the /warn add command.</h3>
35+
* This Subcommand allows staff-members to add a single warn to any user.
36+
*/
37+
public class WarnExportSubcommand extends SlashCommand.Subcommand {
38+
private final NotificationService notificationService;
39+
private final BotConfig botConfig;
40+
private final WarnRepository warnRepository;
41+
private final ExecutorService asyncPool;
42+
43+
/**
44+
* The constructor of this class, which sets the corresponding {@link SubcommandData}.
45+
* @param notificationService The {@link NotificationService}
46+
* @param botConfig The main configuration of the bot
47+
* @param asyncPool The main thread pool for asynchronous operations
48+
* @param warnRepository DAO for interacting with the set of {@link net.javadiscord.javabot.systems.moderation.warn.model.Warn} objects.
49+
*/
50+
public WarnExportSubcommand(NotificationService notificationService, BotConfig botConfig, ExecutorService asyncPool, WarnRepository warnRepository) {
51+
this.notificationService = notificationService;
52+
this.botConfig = botConfig;
53+
this.warnRepository = warnRepository;
54+
this.asyncPool = asyncPool;
55+
setCommandData(new SubcommandData("export", "Exports a list of all warns of a user")
56+
.addOptions(
57+
new OptionData(OptionType.USER, "user", "The user to warn.", true)
58+
)
59+
);
60+
}
61+
62+
@Override
63+
public void execute(@NotNull SlashCommandInteractionEvent event) {
64+
OptionMapping userMapping = event.getOption("user");
65+
if (userMapping == null) {
66+
Responses.replyMissingArguments(event).queue();
67+
return;
68+
}
69+
if (event.getGuild() == null) {
70+
Responses.replyGuildOnly(event).queue();
71+
return;
72+
}
73+
User target = userMapping.getAsUser();
74+
ModerationService service = new ModerationService(notificationService, botConfig, event, warnRepository, asyncPool);
75+
List<Warn> warns = service.getAllWarns(target.getIdLong());
76+
PipedInputStream pis=new PipedInputStream();
77+
try(PrintWriter pw=new PrintWriter(new OutputStreamWriter(new BufferedOutputStream(new PipedOutputStream(pis)), StandardCharsets.UTF_8))){
78+
event.replyEmbeds(new EmbedBuilder()
79+
.setAuthor(target.getAsTag(), null, target.getAvatarUrl())
80+
.setDescription("Export containing all warns of "+target.getAsMention())
81+
.addField("Total number of warns", String.valueOf(warns.stream().count()), false)
82+
.addField("Total number of non-discarded warns (includes expired warns)", String.valueOf(warns.stream().filter(w->!w.isDiscarded()).count()), false)
83+
.addField("Total severity of non-discarded warns (includes expired warns)", String.valueOf(warns.stream().filter(w->!w.isDiscarded()).mapToInt(Warn::getSeverityWeight).sum()), false)
84+
.setFooter(target.getId())
85+
.build())
86+
.addFiles(FileUpload.fromData(pis, "warns"+target.getId()+".txt"))
87+
.queue();
88+
for (Iterator<Warn> it = warns.iterator(); it.hasNext();) {
89+
Warn warn = it.next();
90+
pw.println("Reason: \"" + warn.getReason()+"\"");
91+
pw.println("Severity: " + warn.getSeverity() + "(" + warn.getSeverityWeight() + ")");
92+
pw.println("Warn ID: " + warn.getId());
93+
pw.println("Warned by: " + warn.getWarnedBy());
94+
pw.println("Warned at " + warn.getCreatedAt());
95+
if (it.hasNext()) {
96+
pw.println();
97+
pw.println("============");
98+
pw.println();
99+
}
100+
}
101+
} catch (IOException e) {
102+
ExceptionLogger.capture(e, getClass().getSimpleName());
103+
}
104+
}
105+
}
106+

src/main/java/net/javadiscord/javabot/systems/moderation/warn/WarnsListCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public void execute(@NotNull SlashCommandInteractionEvent event) {
8484
LocalDateTime cutoff = LocalDateTime.now().minusDays(botConfig.get(event.getGuild()).getModerationConfig().getWarnTimeoutDays());
8585
asyncPool.execute(() -> {
8686
try {
87-
event.getHook().sendMessageEmbeds(buildWarnsEmbed(warnRepository.getWarnsByUserId(user.getIdLong(), cutoff), user)).queue();
87+
event.getHook().sendMessageEmbeds(buildWarnsEmbed(warnRepository.getActiveWarnsByUserId(user.getIdLong(), cutoff), user)).queue();
8888
} catch (DataAccessException e) {
8989
ExceptionLogger.capture(e, WarnsListCommand.class.getSimpleName());
9090
}

src/main/java/net/javadiscord/javabot/systems/moderation/warn/WarnsListContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public void execute(UserContextInteractionEvent event) {
5151
LocalDateTime cutoff = LocalDateTime.now().minusDays(botConfig.get(event.getGuild()).getModerationConfig().getWarnTimeoutDays());
5252
asyncPool.execute(() -> {
5353
try {
54-
event.getHook().sendMessageEmbeds(WarnsListCommand.buildWarnsEmbed(warnRepository.getWarnsByUserId(event.getTarget().getIdLong(), cutoff), event.getTarget())).queue();
54+
event.getHook().sendMessageEmbeds(WarnsListCommand.buildWarnsEmbed(warnRepository.getActiveWarnsByUserId(event.getTarget().getIdLong(), cutoff), event.getTarget())).queue();
5555
} catch (DataAccessException e) {
5656
ExceptionLogger.capture(e, WarnsListContext.class.getSimpleName());
5757
}

src/main/java/net/javadiscord/javabot/systems/moderation/warn/dao/WarnRepository.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,13 @@ private Warn read(ResultSet rs) throws SQLException {
133133
* @param cutoff The time after which to look for warns.
134134
* @return A List with all Warns.
135135
*/
136-
public List<Warn> getWarnsByUserId(long userId, LocalDateTime cutoff) {
136+
public List<Warn> getActiveWarnsByUserId(long userId, LocalDateTime cutoff) {
137137
return jdbcTemplate.query("SELECT * FROM warn WHERE user_id = ? AND discarded = FALSE AND created_at > ?",(rs, row)->this.read(rs),
138138
userId, Timestamp.valueOf(cutoff));
139139
}
140+
141+
public List<Warn> getAllWarnsByUserId(long userId) {
142+
return jdbcTemplate.query("SELECT * FROM warn WHERE user_id = ?",(rs, row)->this.read(rs),
143+
userId);
144+
}
140145
}

0 commit comments

Comments
 (0)