Skip to content

Commit 5ea7131

Browse files
committed
Merge remote-tracking branch 'javabot/main' into timeout-on-warn
2 parents f6f9158 + 006382c commit 5ea7131

File tree

6 files changed

+67
-16
lines changed

6 files changed

+67
-16
lines changed

src/main/java/net/javadiscord/javabot/data/config/guild/ModerationConfig.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ public class ModerationConfig extends GuildConfigItem {
6565
* The duration (in hours) to timeout users when they exceeded {@link #timeoutSeverity}.
6666
*/
6767
private int warnTimeoutHours = 2;
68+
69+
/**
70+
* ID of the channel where direct user notifications should be sent to (using private threads).
71+
* @see net.javadiscord.javabot.systems.notification.UserNotificationService
72+
*/
73+
private long notificationThreadChannelId;
6874

6975
/**
7076
* Invite links AutoMod should exclude.
@@ -115,4 +121,8 @@ public Role getAdminRole() {
115121
public Role getExpertRole() {
116122
return this.getGuild().getRoleById(this.expertRoleId);
117123
}
124+
125+
public TextChannel getNotificationThreadChannel() {
126+
return this.getGuild().getTextChannelById(this.notificationThreadChannelId);
127+
}
118128
}

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public void warn(User user, WarnSeverity severity, String reason, Member warnedB
8888
warnRepository.insert(new Warn(user.getIdLong(), warnedBy.getIdLong(), severity, reason));
8989
int totalSeverity = warnRepository.getTotalSeverityWeight(user.getIdLong(), LocalDateTime.now().minusDays(moderationConfig.getWarnTimeoutDays()));
9090
MessageEmbed warnEmbed = buildWarnEmbed(user, warnedBy, severity, totalSeverity, reason);
91-
notificationService.withUser(user).sendDirectMessage(c -> c.sendMessageEmbeds(warnEmbed));
91+
notificationService.withUser(user, warnedBy.getGuild()).sendDirectMessage(c -> c.sendMessageEmbeds(warnEmbed));
9292
notificationService.withGuild(moderationConfig.getGuild()).sendToModerationLog(c -> c.sendMessageEmbeds(warnEmbed));
9393
if (!quiet && channel.getIdLong() != moderationConfig.getLogChannelId()) {
9494
channel.sendMessageEmbeds(warnEmbed).queue();
@@ -111,12 +111,12 @@ public void warn(User user, WarnSeverity severity, String reason, Member warnedB
111111
* @param user The user to clear warns from.
112112
* @param clearedBy The user who cleared the warns.
113113
*/
114-
public void discardAllWarns(User user, User clearedBy) {
114+
public void discardAllWarns(User user, Member clearedBy) {
115115
asyncPool.execute(() -> {
116116
try {
117117
warnRepository.discardAll(user.getIdLong());
118-
MessageEmbed embed = buildClearWarnsEmbed(user, clearedBy);
119-
notificationService.withUser(user).sendDirectMessage(c -> c.sendMessageEmbeds(embed));
118+
MessageEmbed embed = buildClearWarnsEmbed(user, clearedBy.getUser());
119+
notificationService.withUser(user, clearedBy.getGuild()).sendDirectMessage(c -> c.sendMessageEmbeds(embed));
120120
notificationService.withGuild(moderationConfig.getGuild()).sendToModerationLog(c -> c.sendMessageEmbeds(embed));
121121
} catch (DataAccessException e) {
122122
ExceptionLogger.capture(e, ModerationService.class.getSimpleName());
@@ -192,7 +192,7 @@ public List<Warn> getAllWarns(long userId) {
192192
public void timeout(@Nonnull User user, @Nonnull String reason, @Nonnull Member timedOutBy, @Nonnull Duration duration, @Nonnull MessageChannel channel, boolean quiet) {
193193
MessageEmbed timeoutEmbed = buildTimeoutEmbed(user, timedOutBy, reason, duration);
194194
timedOutBy.getGuild().timeoutFor(user, duration).queue(s -> {
195-
notificationService.withUser(user).sendDirectMessage(c -> c.sendMessageEmbeds(timeoutEmbed));
195+
notificationService.withUser(user, timedOutBy.getGuild()).sendDirectMessage(c -> c.sendMessageEmbeds(timeoutEmbed));
196196
notificationService.withGuild(timedOutBy.getGuild()).sendToModerationLog(c -> c.sendMessageEmbeds(timeoutEmbed));
197197
if (!quiet) channel.sendMessageEmbeds(timeoutEmbed).queue();
198198
}, ExceptionLogger::capture);
@@ -210,7 +210,7 @@ public void timeout(@Nonnull User user, @Nonnull String reason, @Nonnull Member
210210
public void removeTimeout(Member member, String reason, Member removedBy, MessageChannel channel, boolean quiet) {
211211
MessageEmbed removeTimeoutEmbed = buildTimeoutRemovedEmbed(member, removedBy, reason);
212212
removedBy.getGuild().removeTimeout(member).queue(s -> {
213-
notificationService.withUser(member.getUser()).sendDirectMessage(c -> c.sendMessageEmbeds(removeTimeoutEmbed));
213+
notificationService.withUser(member.getUser(), removedBy.getGuild()).sendDirectMessage(c -> c.sendMessageEmbeds(removeTimeoutEmbed));
214214
notificationService.withGuild(member.getGuild()).sendToModerationLog(c -> c.sendMessageEmbeds(removeTimeoutEmbed));
215215
if (!quiet) channel.sendMessageEmbeds(removeTimeoutEmbed).queue();
216216
}, ExceptionLogger::capture);
@@ -227,7 +227,7 @@ public void removeTimeout(Member member, String reason, Member removedBy, Messag
227227
*/
228228
public void ban(User user, String reason, Member bannedBy, MessageChannel channel, boolean quiet) {
229229
MessageEmbed banEmbed = buildBanEmbed(user, bannedBy, reason);
230-
user.openPrivateChannel().flatMap(privateChannel -> privateChannel.sendMessageEmbeds(banEmbed)).queue(success -> {
230+
user.openPrivateChannel().flatMap(privateChannel -> privateChannel.sendMessageEmbeds(banEmbed).setContent(moderationConfig.getBanMessageText())).queue(success -> {
231231
banAndSendGuildNotifications(user, reason, bannedBy, channel, quiet, banEmbed);
232232
}, err-> {
233233
banAndSendGuildNotifications(user, reason, bannedBy, channel, quiet, banEmbed);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void execute(@NotNull SlashCommandInteractionEvent event) {
5454
return;
5555
}
5656
User target = userMapping.getAsUser();
57-
new ModerationService(notificationService, botConfig, event.getInteraction(), warnRepository, asyncPool).discardAllWarns(target, event.getUser());
57+
new ModerationService(notificationService, botConfig, event.getInteraction(), warnRepository, asyncPool).discardAllWarns(target, event.getMember());
5858
Responses.success(event, "Warns Discarded", "Successfully discarded all warns from **%s**.", target.getAsTag()).queue();
5959
}
6060
}

src/main/java/net/javadiscord/javabot/systems/notification/NotificationService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ public class NotificationService {
3333
return new UserNotificationService(user);
3434
}
3535

36+
@Contract("_ -> new")
37+
public @NotNull UserNotificationService withUser(User user, Guild guild) {
38+
return new UserNotificationService(user, botConfig.get(guild).getModerationConfig());
39+
}
40+
3641
public @NotNull QOTWGuildNotificationService withQOTW(Guild guild) {
3742
return new QOTWGuildNotificationService(this, guild);
3843
}
Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
package net.javadiscord.javabot.systems.notification;
22

33
import lombok.AccessLevel;
4+
import lombok.AllArgsConstructor;
45
import lombok.RequiredArgsConstructor;
56
import lombok.extern.slf4j.Slf4j;
67
import net.dv8tion.jda.api.entities.User;
8+
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
9+
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel.AutoArchiveDuration;
710
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
811
import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
12+
import net.javadiscord.javabot.data.config.guild.ModerationConfig;
13+
914
import org.jetbrains.annotations.NotNull;
1015

1116
import java.util.function.Function;
@@ -15,18 +20,34 @@
1520
*/
1621
@Slf4j
1722
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
23+
@AllArgsConstructor(access = AccessLevel.PACKAGE)
1824
public final class UserNotificationService extends NotificationService.MessageChannelNotification {
1925
private final User user;
26+
private ModerationConfig config;
2027

2128
/**
2229
* Sends a notification to a {@link User}s' {@link net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel}.
2330
*
2431
* @param function The {@link Function} to use which MUST return a {@link MessageCreateAction}.
2532
*/
2633
public void sendDirectMessage(@NotNull Function<MessageChannel, MessageCreateAction> function) {
27-
user.openPrivateChannel().queue(
28-
channel -> send(channel, function),
29-
error -> log.error("Could not open PrivateChannel with user " + user.getAsTag(), error)
34+
user.openPrivateChannel().flatMap(function::apply).queue(
35+
msg -> {},
36+
error -> {
37+
log.error("Could not open PrivateChannel with user " + user.getAsTag(), error);
38+
if(config != null) {
39+
TextChannel container = config.getNotificationThreadChannel();
40+
if(container != null) {
41+
container
42+
.createThreadChannel("JavaBot notification", true)
43+
.setAutoArchiveDuration(AutoArchiveDuration.TIME_1_HOUR)
44+
.queue(c -> {
45+
c.addThreadMember(user).queue();
46+
send(c, function);
47+
});
48+
}
49+
}
50+
}
3051
);
3152
}
3253
}

src/main/java/net/javadiscord/javabot/util/WebhookUtil.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import club.minnced.discord.webhook.send.WebhookEmbedBuilder;
88
import club.minnced.discord.webhook.send.WebhookMessageBuilder;
99
import club.minnced.discord.webhook.send.component.LayoutComponent;
10+
import net.dv8tion.jda.api.entities.Member;
1011
import net.dv8tion.jda.api.entities.Message;
1112
import net.dv8tion.jda.api.entities.Message.Attachment;
1213
import net.dv8tion.jda.api.entities.MessageEmbed;
@@ -19,6 +20,7 @@
1920
import java.util.Optional;
2021
import java.util.concurrent.CompletableFuture;
2122
import java.util.function.Consumer;
23+
import java.util.function.Function;
2224

2325
/**
2426
* Contains utility methods for dealing with Discord Webhooks.
@@ -90,14 +92,16 @@ public static CompletableFuture<ReadonlyMessage> mirrorMessageToWebhook(@NotNull
9092
.setThreadId(threadId).buildJDA();
9193
WebhookMessageBuilder message = new WebhookMessageBuilder().setContent(newMessageContent)
9294
.setAllowedMentions(AllowedMentions.none())
93-
.setAvatarUrl(originalMessage.getMember().getEffectiveAvatarUrl())
94-
.setUsername(originalMessage.getMember().getEffectiveName());
95+
.setAvatarUrl(transformOrNull(originalMessage.getMember(), Member::getEffectiveAvatarUrl))
96+
.setUsername(transformOrNull(originalMessage.getMember(), Member::getEffectiveName));
9597
if (components != null && !components.isEmpty()) {
9698
message.addComponents(components);
9799
}
98-
if (embeds != null && !embeds.isEmpty()) {
99-
message.addEmbeds(embeds.stream().map(e -> WebhookEmbedBuilder.fromJDA(e).build()).toList());
100+
101+
if (embeds == null || embeds.isEmpty()) {
102+
embeds = originalMessage.getEmbeds();
100103
}
104+
message.addEmbeds(embeds.stream().map(e -> WebhookEmbedBuilder.fromJDA(e).build()).toList());
101105
List<Attachment> attachments = originalMessage.getAttachments();
102106
@SuppressWarnings("unchecked")
103107
CompletableFuture<?>[] futures = new CompletableFuture<?>[attachments.size()];
@@ -106,12 +110,23 @@ public static CompletableFuture<ReadonlyMessage> mirrorMessageToWebhook(@NotNull
106110
futures[i] = attachment.getProxy().download().thenAccept(
107111
is -> message.addFile((attachment.isSpoiler() ? "SPOILER_" : "") + attachment.getFileName(), is));
108112
}
109-
return CompletableFuture.allOf(futures).thenCompose(unused -> client.send(message.build()))
113+
return CompletableFuture.allOf(futures).thenCompose(unused -> sendMessage(client, message))
110114
.whenComplete((result, err) -> {
111115
client.close();
112116
if( err != null) {
113117
ExceptionLogger.capture(err, WebhookUtil.class.getSimpleName());
114118
}
115119
});
116120
}
121+
122+
private static <T, R> R transformOrNull(T toTransform, Function<T, R> transformer) {
123+
return toTransform == null ? null : transformer.apply(toTransform);
124+
}
125+
126+
private static @NotNull CompletableFuture<ReadonlyMessage> sendMessage(JDAWebhookClient client, WebhookMessageBuilder message) {
127+
if(message.isEmpty()) {
128+
message.setContent("<empty message>");
129+
}
130+
return client.send(message.build());
131+
}
117132
}

0 commit comments

Comments
 (0)