[AB-xxx] reworking ban logging to use audit log instead of actively logging or using the banned event

partially fixing broken infraction handling
adding CompletableFutureMap to handle futures easier
updating user display object to also hold name
replaced some references to UserObjects in models with UserDisplay objects
This commit is contained in:
Sheldan
2024-05-05 01:58:26 +02:00
parent ca45137cc6
commit 234aae3783
24 changed files with 279 additions and 259 deletions

View File

@@ -3,8 +3,12 @@ package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.listener.ListenerService;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.listener.UserBannedModel;
import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.core.utils.CompletableFutureMap;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.guild.GuildBanEvent;
import net.dv8tion.jda.api.audit.ActionType;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -12,11 +16,13 @@ import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.List;
@Component
@Slf4j
public class AsyncUserBannedListenerBean extends ListenerAdapter {
@Autowired(required = false)
private List<AsyncUserBannedListener> listenerList;
@@ -27,25 +33,48 @@ public class AsyncUserBannedListenerBean extends ListenerAdapter {
@Autowired
private ListenerService listenerService;
@Autowired
private UserService userService;
@Override
public void onGuildBan(@Nonnull GuildBanEvent event) {
public void onGuildAuditLogEntryCreate(@Nonnull GuildAuditLogEntryCreateEvent event) {
if(listenerList == null) return;
UserBannedModel model = getModel(event);
listenerList.forEach(leaveListener -> listenerService.executeFeatureAwareListener(leaveListener, model, leaveListenerExecutor));
if(event.getEntry().getType().equals(ActionType.BAN)) {
log.info("Handling ban audit log entry created for user {} in server {}.", event.getEntry().getTargetIdLong(), event.getGuild().getIdLong());
CompletableFutureMap<Long, User> longUserCompletableFutureMap = userService.retrieveUsersMapped(Arrays.asList(event.getEntry().getTargetIdLong(), event.getEntry().getUserIdLong()));
longUserCompletableFutureMap.getMainFuture().thenAccept(avoid -> {
User bannedUser = longUserCompletableFutureMap.getElement(event.getEntry().getTargetIdLong());
User banningUser = longUserCompletableFutureMap.getElement(event.getEntry().getUserIdLong());
UserBannedModel model = getModel(event, bannedUser, banningUser);
listenerList.forEach(leaveListener -> listenerService.executeFeatureAwareListener(leaveListener, model, leaveListenerExecutor));
}).exceptionally(throwable -> {
log.warn("Failed to fetch users {} or {} for banned event.", event.getEntry().getTargetIdLong(), event.getEntry().getUserIdLong(), throwable);
UserBannedModel model = getModel(event, null, null);
listenerList.forEach(leaveListener -> listenerService.executeFeatureAwareListener(leaveListener, model, leaveListenerExecutor));
return null;
});
}
}
private UserBannedModel getModel(GuildBanEvent event) {
ServerUser serverUser = ServerUser
private UserBannedModel getModel(GuildAuditLogEntryCreateEvent event, User bannedUser, User banningUser) {
ServerUser bannedServerUser = ServerUser
.builder()
.serverId(event.getGuild().getIdLong())
.userId(event.getUser().getIdLong())
.isBot(event.getUser().isBot())
.userId(event.getEntry().getTargetIdLong())
.build();
ServerUser banningServerUser = ServerUser
.builder()
.serverId(event.getGuild().getIdLong())
.userId(event.getEntry().getUserIdLong())
.build();
return UserBannedModel
.builder()
.bannedUser(serverUser)
.bannedServerUser(bannedServerUser)
.banningUser(banningUser)
.banningServerUser(banningServerUser)
.guild(event.getGuild())
.user(event.getUser())
.reason(event.getEntry().getReason())
.bannedUser(bannedUser)
.build();
}
}

View File

@@ -3,8 +3,12 @@ package dev.sheldan.abstracto.core.listener.async.jda;
import dev.sheldan.abstracto.core.listener.ListenerService;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.models.listener.UserUnBannedModel;
import dev.sheldan.abstracto.core.service.UserService;
import dev.sheldan.abstracto.core.utils.CompletableFutureMap;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.events.guild.GuildUnbanEvent;
import net.dv8tion.jda.api.audit.ActionType;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.events.guild.GuildAuditLogEntryCreateEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -12,6 +16,7 @@ import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.List;
@Component
@@ -27,25 +32,48 @@ public class AsyncUserUnBannedListenerBean extends ListenerAdapter {
@Autowired
private ListenerService listenerService;
@Autowired
private UserService userService;
@Override
public void onGuildUnban(@Nonnull GuildUnbanEvent event) {
public void onGuildAuditLogEntryCreate(@Nonnull GuildAuditLogEntryCreateEvent event) {
if(listenerList == null) return;
UserUnBannedModel model = getModel(event);
listenerList.forEach(leaveListener -> listenerService.executeFeatureAwareListener(leaveListener, model, leaveListenerExecutor));
if(event.getEntry().getType().equals(ActionType.UNBAN)) {
log.info("Handling unBan audit log entry created for user {} in server {}.", event.getEntry().getTargetIdLong(), event.getGuild().getIdLong());
CompletableFutureMap<Long, User> longUserCompletableFutureMap = userService.retrieveUsersMapped(Arrays.asList(event.getEntry().getTargetIdLong(), event.getEntry().getUserIdLong()));
longUserCompletableFutureMap.getMainFuture().thenAccept(avoid -> {
User unBannedUser = longUserCompletableFutureMap.getElement(event.getEntry().getTargetIdLong());
User unBanningUser = longUserCompletableFutureMap.getElement(event.getEntry().getUserIdLong());
UserUnBannedModel model = getModel(event, unBannedUser, unBanningUser);
listenerList.forEach(leaveListener -> listenerService.executeFeatureAwareListener(leaveListener, model, leaveListenerExecutor));
}).exceptionally(throwable -> {
log.warn("Failed to fetch users {} or {} for unbanned event.", event.getEntry().getTargetIdLong(), event.getEntry().getUserIdLong(), throwable);
UserUnBannedModel model = getModel(event, null, null);
listenerList.forEach(leaveListener -> listenerService.executeFeatureAwareListener(leaveListener, model, leaveListenerExecutor));
return null;
});
}
}
private UserUnBannedModel getModel(GuildUnbanEvent event) {
ServerUser serverUser = ServerUser
private UserUnBannedModel getModel(GuildAuditLogEntryCreateEvent event, User unBannedUser, User unBanningUser) {
ServerUser unBannedServerUser = ServerUser
.builder()
.serverId(event.getGuild().getIdLong())
.userId(event.getUser().getIdLong())
.isBot(event.getUser().isBot())
.userId(event.getEntry().getTargetIdLong())
.build();
ServerUser unBanningServerUser = ServerUser
.builder()
.serverId(event.getGuild().getIdLong())
.userId(event.getEntry().getUserIdLong())
.build();
return UserUnBannedModel
.builder()
.unbannedUser(serverUser)
.unBannedServerUser(unBannedServerUser)
.unBanningUser(unBanningUser)
.unBanningServerUser(unBanningServerUser)
.guild(event.getGuild())
.user(event.getUser())
.reason(event.getEntry().getReason())
.unBannedUser(unBannedUser)
.build();
}
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.core.utils.CompletableFutureMap;
import net.dv8tion.jda.api.entities.SelfUser;
import net.dv8tion.jda.api.entities.User;
import org.springframework.beans.factory.annotation.Autowired;
@@ -8,6 +9,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
@@ -30,6 +32,12 @@ public class UserServiceBean implements UserService {
return new CompletableFutureList<>(userFutures);
}
@Override
public CompletableFutureMap<Long, User> retrieveUsersMapped(List<Long> ids) {
return new CompletableFutureMap<>(ids.stream()
.collect(Collectors.toMap(Function.identity(), this::retrieveUserForId)));
}
@Override
public SelfUser getSelfUser() {
return botService.getInstance().getSelfUser();

View File

@@ -1,21 +1,51 @@
package dev.sheldan.abstracto.core.models.frontend;
import dev.sheldan.abstracto.core.models.ServerUser;
import dev.sheldan.abstracto.core.utils.MemberUtils;
import lombok.Builder;
import lombok.Getter;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.User;
@Getter
@Builder
public class UserDisplay {
private String avatarUrl;
private String name;
private String id;
private String discriminator;
private String userMention;
private Long id;
public static UserDisplay fromMember(Member member) {
return builder()
.avatarUrl(member.getEffectiveAvatarUrl())
.name(member.getEffectiveName())
.id(member.getId())
.userMention(MemberUtils.getUserAsMention(member.getIdLong()))
.id(member.getIdLong())
.build();
}
public static UserDisplay fromUser(User user) {
return builder()
.discriminator(user.getDiscriminator())
.avatarUrl(user.getEffectiveAvatarUrl())
.name(user.getEffectiveName())
.userMention(MemberUtils.getUserAsMention(user.getIdLong()))
.id(user.getIdLong())
.build();
}
public static UserDisplay fromServerUser(ServerUser user) {
return builder()
.userMention(MemberUtils.getUserAsMention(user.getUserId()))
.id(user.getUserId())
.build();
}
public static UserDisplay fromId(Long id) {
return builder()
.userMention(MemberUtils.getUserAsMention(id))
.id(id)
.build();
}
}

View File

@@ -12,9 +12,12 @@ import net.dv8tion.jda.api.entities.User;
@Setter
@Builder
public class UserBannedModel implements FeatureAwareListenerModel {
private ServerUser bannedUser;
private User user;
private ServerUser bannedServerUser;
private ServerUser banningServerUser;
private User bannedUser;
private User banningUser;
private Guild guild;
private String reason;
@Override
public Long getServerId() {
return guild.getIdLong();

View File

@@ -12,9 +12,12 @@ import net.dv8tion.jda.api.entities.User;
@Setter
@Builder
public class UserUnBannedModel implements FeatureAwareListenerModel {
private ServerUser unbannedUser;
private User user;
private ServerUser unBannedServerUser;
private ServerUser unBanningServerUser;
private User unBannedUser;
private User unBanningUser;
private Guild guild;
private String reason;
@Override
public Long getServerId() {
return guild.getIdLong();

View File

@@ -11,14 +11,18 @@ import net.dv8tion.jda.api.entities.User;
@Setter
@Builder
public class UserDisplay {
private Long userId;
private Long id;
private String userMention;
private String discriminator;
private String name;
public static UserDisplay fromUser(User user) {
return UserDisplay
.builder()
.userMention(MemberUtils.getUserAsMention(user.getIdLong()))
.userId(user.getIdLong())
.name(user.getEffectiveName())
.discriminator(user.getDiscriminator())
.id(user.getIdLong())
.build();
}
@@ -26,7 +30,7 @@ public class UserDisplay {
return UserDisplay
.builder()
.userMention(MemberUtils.getUserAsMention(serverUser.getUserId()))
.userId(serverUser.getUserId())
.id(serverUser.getUserId())
.build();
}
@@ -34,7 +38,7 @@ public class UserDisplay {
return UserDisplay
.builder()
.userMention(MemberUtils.getUserAsMention(id))
.userId(id)
.id(id)
.build();
}

View File

@@ -1,6 +1,7 @@
package dev.sheldan.abstracto.core.service;
import dev.sheldan.abstracto.core.utils.CompletableFutureList;
import dev.sheldan.abstracto.core.utils.CompletableFutureMap;
import net.dv8tion.jda.api.entities.SelfUser;
import net.dv8tion.jda.api.entities.User;
@@ -10,5 +11,6 @@ import java.util.concurrent.CompletableFuture;
public interface UserService {
CompletableFuture<User> retrieveUserForId(Long id);
CompletableFutureList<User> retrieveUsers(List<Long> ids);
CompletableFutureMap<Long, User> retrieveUsersMapped(List<Long> ids);
SelfUser getSelfUser();
}

View File

@@ -0,0 +1,49 @@
package dev.sheldan.abstracto.core.utils;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@Getter
@Slf4j
public class CompletableFutureMap<L, T> {
private final CompletableFuture<Void> mainFuture;
private final Map<L, CompletableFuture<T>> futures;
public CompletableFutureMap(Map<L ,CompletableFuture<T>> futures) {
this.mainFuture = CompletableFuture.allOf(futures.values().toArray(new CompletableFuture[0]));
this.futures = futures;
}
public List<T> getObjects() {
List<T> result = new ArrayList<>();
futures.values().forEach(future -> {
if(!future.isCompletedExceptionally()) {
result.add(future.join());
} else {
try {
future.join();
} catch (Exception exception) {
log.warn("Future completed with exception.", exception);
}
}
});
return result;
}
public T getElement(L key) {
if(!getFutures().containsKey(key)) {
return null;
}
CompletableFuture<T> future = getFutures().get(key);
if(!future.isCompletedExceptionally()) {
return future.join();
} else {
return null;
}
}
}