[AB-138] improving logging at various places fixing various issues regarding async commands and exception handling, fixing role role calculation being done twice

This commit is contained in:
Sheldan
2020-10-07 09:29:56 +02:00
parent a391381ff6
commit 0145e7670d
165 changed files with 1129 additions and 513 deletions

View File

@@ -15,7 +15,6 @@ import org.springframework.stereotype.Component;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component @Component
public class SetAssignableRolePosition extends AbstractConditionableCommand { public class SetAssignableRolePosition extends AbstractConditionableCommand {
@@ -24,14 +23,14 @@ public class SetAssignableRolePosition extends AbstractConditionableCommand {
private AssignableRolePlaceService service; private AssignableRolePlaceService service;
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
checkParameters(commandContext); checkParameters(commandContext);
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
String name = (String) parameters.get(0); String name = (String) parameters.get(0);
FullEmote emote = (FullEmote) parameters.get(1); FullEmote emote = (FullEmote) parameters.get(1);
Integer newPosition = (Integer) parameters.get(2); Integer newPosition = (Integer) parameters.get(2);
return service.setEmoteToPosition(commandContext.getUserInitiatedContext().getServer(), name, emote, newPosition) service.setEmoteToPosition(commandContext.getUserInitiatedContext().getServer(), name, emote, newPosition);
.thenApply(aVoid -> CommandResult.fromSuccess()); return CommandResult.fromSuccess();
} }
@Override @Override
@@ -46,7 +45,6 @@ public class SetAssignableRolePosition extends AbstractConditionableCommand {
.module(AssignableRoleModule.ASSIGNABLE_ROLES) .module(AssignableRoleModule.ASSIGNABLE_ROLES)
.templated(true) .templated(true)
.causesReaction(true) .causesReaction(true)
.async(true)
.supportsEmbedException(true) .supportsEmbedException(true)
.parameters(parameters) .parameters(parameters)
.help(helpInfo) .help(helpInfo)

View File

@@ -71,6 +71,7 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
} }
MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote(); MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote();
if(assignablePlacePost.getAssignablePlace().getActive()) { if(assignablePlacePost.getAssignablePlace().getActive()) {
log.info("User {} added reaction to assignable role place {} in server {}. Handling added event.", userAdding.getUserReference().getId(), assignablePlacePost.getId(), event.getGuild().getId());
addAppropriateRoles(event, reaction, assignablePlacePost, reactionEmote, userAdding); addAppropriateRoles(event, reaction, assignablePlacePost, reactionEmote, userAdding);
} else { } else {
reaction.removeReaction(event.getUser()).submit(); reaction.removeReaction(event.getUser()).submit();
@@ -84,13 +85,16 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
AssignableRolePlace assignableRolePlace = assignablePlacePost.getAssignablePlace(); AssignableRolePlace assignableRolePlace = assignablePlacePost.getAssignablePlace();
List<CompletableFuture<Void>> futures = new ArrayList<>(); List<CompletableFuture<Void>> futures = new ArrayList<>();
for (AssignableRole assignableRole : assignablePlacePost.getAssignableRoles()) { for (AssignableRole assignableRole : assignablePlacePost.getAssignableRoles()) {
log.trace("Checking emote {} if it was reaction for assignable role place.", assignableRole.getEmote().getId());
if (emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) { if (emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) {
if(assignableRolePlace.getUniqueRoles()) { if(assignableRolePlace.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles configured. Removing existing reactions and roles.", assignableRolePlace.getId());
Optional<AssignedRoleUser> byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(userAdding); Optional<AssignedRoleUser> byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(userAdding);
byUserInServer.ifPresent(user -> futures.add(assignableRolePlaceService.removeExistingReactionsAndRoles(assignableRolePlace, user))); byUserInServer.ifPresent(user -> futures.add(assignableRolePlaceService.removeExistingReactionsAndRoles(assignableRolePlace, user)));
} }
Long assignableRoleId = assignableRole.getId(); Long assignableRoleId = assignableRole.getId();
log.info("User added {} reaction {} and gets assignable role {} in server {}.", userAdding.getUserReference().getId(), assignableRole.getEmote().getId(), assignableRoleId, userAdding.getServerReference().getId());
CompletableFuture<Void> roleAdditionFuture = assignableRoleServiceBean.assignAssignableRoleToUser(assignableRoleId, event.getMember()); CompletableFuture<Void> roleAdditionFuture = assignableRoleServiceBean.assignAssignableRoleToUser(assignableRoleId, event.getMember());
futures.add(CompletableFuture.allOf(roleAdditionFuture)); futures.add(CompletableFuture.allOf(roleAdditionFuture));
@@ -99,6 +103,7 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
} }
} }
if(!validReaction) { if(!validReaction) {
log.trace("Reaction was not found in the configuration of assignable role place {}, removing reaction.", assignableRolePlace.getId());
futures.add(reaction.removeReaction(event.getUser()).submit()); futures.add(reaction.removeReaction(event.getUser()).submit());
} }
Long assignableRolePlaceId = assignableRolePlace.getId(); Long assignableRolePlaceId = assignableRolePlace.getId();
@@ -112,9 +117,11 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(assignableRolePlaceId); AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(assignableRolePlaceId);
AUserInAServer userInAServer = userInServerManagementService.loadUser(userAdding); AUserInAServer userInAServer = userInServerManagementService.loadUser(userAdding);
if(place.getUniqueRoles()) { if(place.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles. Deleting all existing references.", assignableRolePlaceId);
assignableRoleServiceBean.clearAllRolesOfUserInPlace(place, userInAServer); assignableRoleServiceBean.clearAllRolesOfUserInPlace(place, userInAServer);
} }
AssignableRole role = assignableRoleManagementService.getRoleForReactionEmote(reactionEmote, place); AssignableRole role = assignableRoleManagementService.getRoleForReactionEmote(reactionEmote, place);
log.info("Adding role to assignable role {} to user {} in server {}.", role.getId(), userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
assignableRoleServiceBean.addRoleToUser(role.getId(), userInAServer); assignableRoleServiceBean.addRoleToUser(role.getId(), userInAServer);
} }

View File

@@ -49,6 +49,8 @@ public class AssignablePostReactionRemoved implements ReactedRemovedListener {
assignablePlacePost.getAssignableRoles().forEach(assignableRole -> { assignablePlacePost.getAssignableRoles().forEach(assignableRole -> {
if(emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) { if(emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) {
Long assignableRoleId = assignableRole.getId(); Long assignableRoleId = assignableRole.getId();
log.info("Removing assignable role {} for user {} in server {} from assignable role place {}.", assignableRoleId,
userRemoving.getUserReference().getId(), userRemoving.getServerReference().getId(), assignablePlacePost.getAssignablePlace().getId());
assignableRoleService.fullyRemoveAssignableRoleFromUser(assignableRole, event.getMember()).exceptionally(throwable -> { assignableRoleService.fullyRemoveAssignableRoleFromUser(assignableRole, event.getMember()).exceptionally(throwable -> {
log.error("Failed to remove assignable role {} from user {}.", assignableRoleId, event.getMember(), throwable); log.error("Failed to remove assignable role {} from user {}.", assignableRoleId, event.getMember(), throwable);
return null; return null;

View File

@@ -109,7 +109,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
} }
@Override @Override
public CompletableFuture<Void> setEmoteToPosition(AServer server, String placeName, FullEmote emote, Integer position) { public void setEmoteToPosition(AServer server, String placeName, FullEmote emote, Integer position) {
if(isPositionUsed(server, placeName, position)) { if(isPositionUsed(server, placeName, position)) {
throw new AbstractoTemplatedException("Position is already used", "assignable_role_place_position_exists_exception"); throw new AbstractoTemplatedException("Position is already used", "assignable_role_place_position_exists_exception");
} }
@@ -118,12 +118,15 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
} }
Integer emoteId = emote.getFakeEmote().getId(); Integer emoteId = emote.getFakeEmote().getId();
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName); AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName);
log.info("Setting emote {} to position {} in assignable role place {} in server {}.",
emoteId, position, assignableRolePlace.getId(), assignableRolePlace.getServer().getId());
Optional<AssignableRole> emoteOptional = assignableRolePlace.getAssignableRoles().stream().filter(role -> role.getEmote().getId().equals(emoteId)).findFirst(); Optional<AssignableRole> emoteOptional = assignableRolePlace.getAssignableRoles().stream().filter(role -> role.getEmote().getId().equals(emoteId)).findFirst();
if(emoteOptional.isPresent()) { if(emoteOptional.isPresent()) {
AssignableRole toChange = emoteOptional.get(); AssignableRole toChange = emoteOptional.get();
toChange.setPosition(position); toChange.setPosition(position);
} else {
throw new EmoteNotInAssignableRolePlaceException(emote, placeName);
} }
throw new EmoteNotInAssignableRolePlaceException(emote, placeName);
} }
@Override @Override
@@ -145,6 +148,8 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
boolean emoteUsable = true; boolean emoteUsable = true;
if(fakeEmote.getEmote() != null) { if(fakeEmote.getEmote() != null) {
// it only may be unusable if its a custom emote // it only may be unusable if its a custom emote
log.trace("Using custom emote {} to create assignable role {} for assignable role place {} in server {}.",
fakeEmote.getEmote().getId(), roleId, placeId, serverId);
emoteUsable = emoteService.isEmoteUsableByBot(fakeEmote.getEmote()) && fakeEmote.getEmote().isAvailable(); emoteUsable = emoteService.isEmoteUsableByBot(fakeEmote.getEmote()) && fakeEmote.getEmote().isAvailable();
} }
if(emoteUsable) { if(emoteUsable) {
@@ -152,13 +157,17 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId)); existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId));
if(!assignableRolePlace.getMessagePosts().isEmpty()){ if(!assignableRolePlace.getMessagePosts().isEmpty()){
log.trace("There are already message posts on for the assignable role place {}.", assignableRolePlace.getId());
AssignableRolePlacePost latestPost = existingMessagePosts.get(assignableRolePlace.getMessagePosts().size() - 1); AssignableRolePlacePost latestPost = existingMessagePosts.get(assignableRolePlace.getMessagePosts().size() - 1);
AssignablePostMessage model = prepareAssignablePostMessageModel(assignableRolePlace); AssignablePostMessage model = prepareAssignablePostMessageModel(assignableRolePlace);
boolean forceNewMessage = latestPost.getAssignableRoles().size() >= 20;
log.info("We need to add a new message post {} for assignable role place {} in server {} in channel {}.",
forceNewMessage, placeId, serverId, assignableRolePlace.getChannel().getId());
AssignablePostRole newAssignableRole = AssignablePostRole AssignablePostRole newAssignableRole = AssignablePostRole
.builder() .builder()
.description(description) .description(description)
.emote(fakeEmote) .emote(fakeEmote)
.forceNewMessage(latestPost.getAssignableRoles().size() >= 20) .forceNewMessage(forceNewMessage)
.build(); .build();
model.getRoles().add(newAssignableRole); model.getRoles().add(newAssignableRole);
MessageToSend messageToSend = templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model); MessageToSend messageToSend = templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model);
@@ -167,15 +176,19 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
if(channelOptional.isPresent()) { if(channelOptional.isPresent()) {
TextChannel textChannel = channelOptional.get(); TextChannel textChannel = channelOptional.get();
if(latestPost.getAssignableRoles().size() < 20) { if(latestPost.getAssignableRoles().size() < 20) {
return addReactionToExistingAssignableRolePlacePost(fakeEmote, description, assignableRolePlace, placeId, roleId, serverId, latestPost, messageToSend, textChannel); log.trace("Adding reaction to existing post {} in channel {} in server {} for assignable role place {}.",
latestPost.getId(), assignableRolePlace.getChannel().getId(), serverId, placeId);
return addReactionToExistingAssignableRolePlacePost(fakeEmote, description, roleId, latestPost, messageToSend, textChannel);
} else { } else {
return addNewMessageToAssignableRolePlace(placeName, fakeEmote, description, roleId, serverId, messageToSend, textChannel); log.trace("Adding new post to assignable role place {} in channel {} in server {}.",
placeId, assignableRolePlace.getChannel().getId(), server.getId());
return addNewMessageToAssignableRolePlace(placeId, fakeEmote, description, roleId, serverId, messageToSend, textChannel);
} }
} else { } else {
throw new ChannelNotFoundException(latestPost.getUsedChannel().getId()); throw new ChannelNotFoundException(latestPost.getUsedChannel().getId());
} }
} else { } else {
log.info("Added emote to assignable place {} in server {}, but no message post yet.", placeName, serverId); log.trace("Added emote to assignable place {} in server {}, but no message post yet.", placeId, serverId);
self.addAssignableRoleInstanceWithoutPost(placeId, roleId, fakeEmote, description, serverId); self.addAssignableRoleInstanceWithoutPost(placeId, roleId, fakeEmote, description, serverId);
} }
} else { } else {
@@ -184,41 +197,50 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
private CompletableFuture<Void> addReactionToExistingAssignableRolePlacePost(FullEmote fakeEmote, String description, AssignableRolePlace assignableRolePlace, Long placeId, Long roleId, Long serverId, AssignableRolePlacePost latestPost, MessageToSend messageToSend, TextChannel textChannel) { private CompletableFuture<Void> addReactionToExistingAssignableRolePlacePost(FullEmote fakeEmote, String description, Long roleId, AssignableRolePlacePost latestPost, MessageToSend messageToSend, TextChannel textChannel) {
// TODO maybe refactor to use the same message object, so we dont need to retrieve it twice and do in parallel // TODO maybe refactor to use the same message object, so we dont need to retrieve it twice and do in parallel
Long serverId = latestPost.getAssignablePlace().getServer().getId();
Long placeId = latestPost.getAssignablePlace().getId();
Long latestPostId = latestPost.getId();
int messagePostSize = latestPost.getAssignablePlace().getMessagePosts().size();
return textChannel.retrieveMessageById(latestPost.getId()).submit() return textChannel.retrieveMessageById(latestPost.getId()).submit()
.thenCompose(message -> messageService.addReactionToMessageWithFuture(fakeEmote.getFakeEmote(), serverId, message))
.thenCompose(aVoid -> {
MessageEmbed embedToUse = messageToSend.getEmbeds().get(assignableRolePlace.getMessagePosts().size() - 1);
return channelService.editEmbedMessageInAChannel(embedToUse, textChannel, latestPost.getId());
})
.thenCompose(message -> { .thenCompose(message -> {
self.addAssignableRoleInstanceWithPost(message.getIdLong(), placeId, roleId, description, fakeEmote, serverId); log.trace("Adding reaction to message {} in server {} for assignable role place {}.", message.getId(), serverId, placeId);
return CompletableFuture.completedFuture(null); return messageService.addReactionToMessageWithFuture(fakeEmote.getFakeEmote(), serverId, message);
}).thenCompose(aVoid -> {
log.trace("Editing embed for assignable role place post {} in assignable role place {} in server {}.", latestPostId, placeId, serverId);
MessageEmbed embedToUse = messageToSend.getEmbeds().get(messagePostSize - 1);
return channelService.editEmbedMessageInAChannel(embedToUse, textChannel, latestPostId);
}).thenAccept(message ->
self.addAssignableRoleInstanceWithPost(message.getIdLong(), placeId, roleId, description, fakeEmote, serverId)
);
}
private CompletableFuture<Void> addNewMessageToAssignableRolePlace(Long placeId, FullEmote fakeEmote, String description, Long roleId, Long serverId, MessageToSend messageToSend, TextChannel textChannel) {
MessageEmbed embedToUse = messageToSend.getEmbeds().get(messageToSend.getEmbeds().size() - 1);
return channelService.sendEmbedToChannel(embedToUse, textChannel)
.thenCompose(message -> {
log.trace("Adding reaction for role {} to newly created message {} for assignable role place {} in server {}.", roleId, message.getId(), placeId, serverId);
return messageService.addReactionToMessageWithFuture(fakeEmote.getFakeEmote(), serverId, message)
.thenAccept(aVoid ->
self.addNewlyCreatedAssignablePlacePost(placeId, description, roleId, serverId, message, fakeEmote)
);
}); });
} }
private CompletableFuture<Void> addNewMessageToAssignableRolePlace(String placeName, FullEmote fakeEmote, String description, Long roleId, Long serverId, MessageToSend messageToSend, TextChannel textChannel) {
MessageEmbed embedToUse = messageToSend.getEmbeds().get(messageToSend.getEmbeds().size() - 1);
return channelService.sendEmbedToChannel(embedToUse, textChannel)
.thenCompose(message -> messageService.addReactionToMessageWithFuture(fakeEmote.getFakeEmote(), serverId, message).thenAccept(aVoid ->
self.addNewlyCreatedAssignablePlacePost(placeName, description, roleId, serverId, textChannel, message, fakeEmote)
));
}
@Transactional @Transactional
public void addNewlyCreatedAssignablePlacePost(String placeName, String description,Long roleId, Long serverId, TextChannel textChannel, Message message, FullEmote fakeEmote) { public void addNewlyCreatedAssignablePlacePost(Long placeId, String description,Long roleId, Long serverId, Message message, FullEmote fakeEmote) {
AChannel loadedChannel = channelManagementService.loadChannel(textChannel.getIdLong()); log.info("Storing newly created assignable role place post {} for place {} in server {}.", message.getId(), placeId, serverId);
AServer loadedServer = serverManagementService.loadOrCreate(serverId);
ARole role = roleManagementService.findRole(roleId); ARole role = roleManagementService.findRole(roleId);
AssignableRolePlace loadedPlace = rolePlaceManagementService.findByServerAndKey(loadedServer, placeName); AssignableRolePlace loadedPlace = rolePlaceManagementService.findByPlaceId(placeId);
AEmote emote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), serverId, false); AEmote emote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), serverId, false);
emote.setChangeable(false); emote.setChangeable(false);
log.trace("Setting emote {} to not changeable, because it is part of an assignable role place {} in server {}.", emote.getId(), placeId, serverId);
AssignableRolePlacePost newPost = AssignableRolePlacePost AssignableRolePlacePost newPost = AssignableRolePlacePost
.builder() .builder()
.id(message.getIdLong()) .id(message.getIdLong())
.usedChannel(loadedChannel) .usedChannel(loadedPlace.getChannel())
.assignablePlace(loadedPlace) .assignablePlace(loadedPlace)
.build(); .build();
@@ -228,25 +250,32 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
@Transactional @Transactional
public void addAssignableRoleInstanceWithPost(Long messageId, Long placeId, Long roleId, String description, FullEmote fakeEmote, Long serverId) { public void addAssignableRoleInstanceWithPost(Long messageId, Long placeId, Long roleId, String description, FullEmote fakeEmote, Long serverId) {
log.info("Storing newly created assignable role {} to post {} to assignable role place {} in server {}.", roleId, messageId, placeId, serverId);
AEmote emote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), serverId, false); AEmote emote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), serverId, false);
emote.setChangeable(false); emote.setChangeable(false);
log.trace("Setting emote {} to not changeable, because it is part of an assignable role place {} in server {}.", emote.getId(), placeId, serverId);
assignableRoleManagementServiceBean.addRoleToPlace(placeId, emote.getId(), roleId, description, messageId); assignableRoleManagementServiceBean.addRoleToPlace(placeId, emote.getId(), roleId, description, messageId);
} }
@Transactional @Transactional
public void addAssignableRoleInstanceWithoutPost(Long placeId, Long roleId, FullEmote fakeEmote, String description, Long serverId) { public void addAssignableRoleInstanceWithoutPost(Long placeId, Long roleId, FullEmote fakeEmote, String description, Long serverId) {
log.info("Storing newly created assignable role {} without post to assignable role place {} in server {}.", roleId, placeId, serverId);
AEmote emote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), serverId, false); AEmote emote = emoteManagementService.createEmote(null, fakeEmote.getFakeEmote(), serverId, false);
emote.setChangeable(false); emote.setChangeable(false);
log.trace("Setting emote {} to not changeable, because it is part of an assignable role place {} in server {}.", emote.getId(), placeId, serverId);
assignableRoleManagementServiceBean.addRoleToPlace(placeId, emote.getId(), roleId, description); assignableRoleManagementServiceBean.addRoleToPlace(placeId, emote.getId(), roleId, description);
} }
@Override @Override
public CompletableFuture<Void> removeRoleFromAssignableRolePlace(AServer server, String placeName, FullEmote emote) { public CompletableFuture<Void> removeRoleFromAssignableRolePlace(AServer server, String placeName, FullEmote emote) {
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName); AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName);
Long assignableRolePlaceId = assignableRolePlace.getId();
for (AssignableRole assignableRole : assignableRolePlace.getAssignableRoles()) { for (AssignableRole assignableRole : assignableRolePlace.getAssignableRoles()) {
if(emoteService.compareAEmote(assignableRole.getEmote(), emote.getFakeEmote())) { if(emoteService.compareAEmote(assignableRole.getEmote(), emote.getFakeEmote())) {
log.info("Removing assignable role {} identified by emote {} from assignable role place {} in server {}.",
assignableRole.getId(), assignableRole.getEmote().getId(), assignableRolePlace.getId(), assignableRolePlace.getServer().getId());
return removeRoleFromAssignablePlace(assignableRole, assignableRolePlace).thenAccept(aVoid -> return removeRoleFromAssignablePlace(assignableRole, assignableRolePlace).thenAccept(aVoid ->
self.deleteAssignableRoleFromPlace(server.getId(), placeName, assignableRole.getId()) self.deleteAssignableRoleFromPlace(assignableRolePlaceId, assignableRole.getId())
); );
} }
} }
@@ -254,9 +283,9 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
} }
@Transactional @Transactional
public void deleteAssignableRoleFromPlace(Long serverId, String placeName, Long assignableRoleId) { public void deleteAssignableRoleFromPlace(Long placeId, Long assignableRoleId) {
AServer server = serverManagementService.loadOrCreate(serverId); AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByPlaceId(placeId);
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName); log.info("Deleting the entry for assignable role {} in assignable role place {}.", assignableRoleId, placeId);
Optional<AssignableRole> roleToRemoveOptional = assignableRolePlace.getAssignableRoles().stream().filter(role -> role.getId().equals(assignableRoleId)).findAny(); Optional<AssignableRole> roleToRemoveOptional = assignableRolePlace.getAssignableRoles().stream().filter(role -> role.getId().equals(assignableRoleId)).findAny();
roleToRemoveOptional.ifPresent(assignableRole -> { roleToRemoveOptional.ifPresent(assignableRole -> {
assignableRolePlace.getAssignableRoles().remove(assignableRole); assignableRolePlace.getAssignableRoles().remove(assignableRole);
@@ -272,11 +301,13 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
List<AssignableRole> assignableRoles = assignableRolePlace.getAssignableRoles(); List<AssignableRole> assignableRoles = assignableRolePlace.getAssignableRoles();
assignableRoles.sort(Comparator.comparing(AssignableRole::getPosition)); assignableRoles.sort(Comparator.comparing(AssignableRole::getPosition));
Long messageId = post.getId(); Long messageId = post.getId();
log.trace("Removing field describing assignable role {} in assignable role place {} from post {}.", role.getId(), assignableRolePlace.getId(), messageId);
CompletableFuture<Message> fieldEditing = channelService.removeFieldFromMessage(textChannel, messageId, assignableRoles.indexOf(role)); CompletableFuture<Message> fieldEditing = channelService.removeFieldFromMessage(textChannel, messageId, assignableRoles.indexOf(role));
log.trace("Clearing reaction for emote {} on assignable role post {} in assignable role place {}.", role.getEmote().getId(), messageId, assignableRolePlace.getId());
CompletableFuture<Void> reactionRemoval = messageService.clearReactionFromMessageWithFuture(role.getEmote(), assignableRolePlace.getServer().getId(), role.getAssignableRolePlacePost().getUsedChannel().getId(), role.getAssignableRolePlacePost().getId()); CompletableFuture<Void> reactionRemoval = messageService.clearReactionFromMessageWithFuture(role.getEmote(), assignableRolePlace.getServer().getId(), role.getAssignableRolePlacePost().getUsedChannel().getId(), role.getAssignableRolePlacePost().getId());
return CompletableFuture.allOf(fieldEditing, reactionRemoval); return CompletableFuture.allOf(fieldEditing, reactionRemoval);
} else { } else {
// this case comes from the situation in which, the emote was deleted ant he initial post setup failed // this case comes from the situation in which, the emote was deleted and he initial post setup failed
log.warn("Reaction {} to remove does not have a post attached. The post needs to be setup again, it is most likely not functioning currently anyway.", role.getEmote().getEmoteId()); log.warn("Reaction {} to remove does not have a post attached. The post needs to be setup again, it is most likely not functioning currently anyway.", role.getEmote().getEmoteId());
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
@@ -285,14 +316,16 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
@Override @Override
public CompletableFuture<Void> setupAssignableRolePlace(AServer server, String name) { public CompletableFuture<Void> setupAssignableRolePlace(AServer server, String name) {
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, name); AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, name);
log.info("Setting up assignable role place {} in server {} towards channel {}.", assignableRolePlace.getId(), server.getId(), assignableRolePlace.getChannel().getId());
List<CompletableFuture<Void>> oldPostDeletionFutures = deleteExistingMessagePostsForPlace(assignableRolePlace); List<CompletableFuture<Void>> oldPostDeletionFutures = deleteExistingMessagePostsForPlace(assignableRolePlace);
assignableRolePlace.getMessagePosts().clear(); assignableRolePlace.getMessagePosts().clear();
assignableRolePlace.getAssignableRoles().forEach(assignableRole -> assignableRolePlace.getAssignableRoles().forEach(assignableRole ->
assignableRole.setAssignableRolePlacePost(null) assignableRole.setAssignableRolePlacePost(null)
); );
Long serverId = server.getId(); Long serverId = server.getId();
Long assignablePlaceId = assignableRolePlace.getId();
return CompletableFuture.allOf(oldPostDeletionFutures.toArray(new CompletableFuture[0])) return CompletableFuture.allOf(oldPostDeletionFutures.toArray(new CompletableFuture[0]))
.thenCompose(aVoid -> self.createAssignableRolePlacePosts(serverId, name)); .thenCompose(aVoid -> self.createAssignableRolePlacePosts(serverId, assignablePlaceId));
} }
@Override @Override
@@ -303,6 +336,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
@Override @Override
public CompletableFuture<Void> refreshAssignablePlacePosts(AssignableRolePlace place) { public CompletableFuture<Void> refreshAssignablePlacePosts(AssignableRolePlace place) {
log.info("Refreshing assignable role place posts for assignable role place {} in server {}.", place.getId(), place.getServer().getId());
MessageToSend messageToSend = renderAssignablePlacePosts(place); MessageToSend messageToSend = renderAssignablePlacePosts(place);
List<AssignableRolePlacePost> existingMessagePosts = place.getMessagePosts(); List<AssignableRolePlacePost> existingMessagePosts = place.getMessagePosts();
existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId)); existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId));
@@ -313,6 +347,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
TextChannel textChannel = channelOptional.get(); TextChannel textChannel = channelOptional.get();
Iterator<MessageEmbed> iterator = messageToSend.getEmbeds().iterator(); Iterator<MessageEmbed> iterator = messageToSend.getEmbeds().iterator();
place.getMessagePosts().forEach(post -> { place.getMessagePosts().forEach(post -> {
log.trace("Refreshing the posts for message post {} in channel {} in assignable role place {} in server {}.", post.getId(), textChannel.getId(), place.getId(), place.getServer().getId());
CompletableFuture<Message> messageCompletableFuture = channelService.editEmbedMessageInAChannel(iterator.next(), textChannel, post.getId()); CompletableFuture<Message> messageCompletableFuture = channelService.editEmbedMessageInAChannel(iterator.next(), textChannel, post.getId());
futures.add(messageCompletableFuture); futures.add(messageCompletableFuture);
}); });
@@ -326,12 +361,14 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
List<AssignableRolePlacePost> existingMessagePosts = place.getMessagePosts(); List<AssignableRolePlacePost> existingMessagePosts = place.getMessagePosts();
if(!existingMessagePosts.isEmpty()) { if(!existingMessagePosts.isEmpty()) {
MessageToSend renderedMessage = renderAssignablePlacePosts(place); MessageToSend renderedMessage = renderAssignablePlacePosts(place);
log.trace("There are {} current posts known for the assignable role place {}.", existingMessagePosts.size(), place.getId());
existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId)); existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId));
AssignableRolePlacePost latestPost = existingMessagePosts.get(0); AssignableRolePlacePost firstPost = existingMessagePosts.get(0);
Long channelId = latestPost.getUsedChannel().getId(); Long channelId = firstPost.getUsedChannel().getId();
Optional<TextChannel> channelOptional = channelService.getTextChannelInGuild(place.getServer().getId(), channelId); Optional<TextChannel> channelOptional = channelService.getTextChannelInGuild(place.getServer().getId(), channelId);
if(channelOptional.isPresent()) { if(channelOptional.isPresent()) {
return channelService.editEmbedMessageInAChannel(renderedMessage.getEmbeds().get(0), channelOptional.get(), latestPost.getId()).thenCompose(message -> CompletableFuture.completedFuture(null)); log.info("Refreshing text for assignable role place {} in channel {} in post {}.", place.getId(), channelId, firstPost.getId());
return channelService.editEmbedMessageInAChannel(renderedMessage.getEmbeds().get(0), channelOptional.get(), firstPost.getId()).thenCompose(message -> CompletableFuture.completedFuture(null));
} }
throw new ChannelNotFoundException(channelId); throw new ChannelNotFoundException(channelId);
} }
@@ -350,9 +387,11 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
private List<CompletableFuture<Void>> deleteExistingMessagePostsForPlace(AssignableRolePlace assignableRolePlace) { private List<CompletableFuture<Void>> deleteExistingMessagePostsForPlace(AssignableRolePlace assignableRolePlace) {
List<CompletableFuture<Void>> oldPostDeletionFutures = new ArrayList<>(); List<CompletableFuture<Void>> oldPostDeletionFutures = new ArrayList<>();
assignableRolePlace.getMessagePosts().forEach(assignableRolePlacePost -> assignableRolePlace.getMessagePosts().forEach(assignableRolePlacePost -> {
oldPostDeletionFutures.add(messageService.deleteMessageInChannelInServer(assignableRolePlace.getServer().getId(), assignableRolePlacePost.getUsedChannel().getId(), assignableRolePlacePost.getId())) log.info("Deleting existing message post with id {} in channel{} for assignable role place {} in server {}.",
); assignableRolePlacePost.getId(), assignableRolePlacePost.getUsedChannel().getId(), assignableRolePlace.getId(), assignableRolePlace.getServer().getId());
oldPostDeletionFutures.add(messageService.deleteMessageInChannelInServer(assignableRolePlace.getServer().getId(), assignableRolePlacePost.getUsedChannel().getId(), assignableRolePlacePost.getId()));
});
return oldPostDeletionFutures; return oldPostDeletionFutures;
} }
@@ -484,6 +523,8 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
if(firstEmoteOptional.isPresent() && secondEmoteOptional.isPresent()) { if(firstEmoteOptional.isPresent() && secondEmoteOptional.isPresent()) {
AssignableRole firstRole = firstEmoteOptional.get(); AssignableRole firstRole = firstEmoteOptional.get();
AssignableRole secondRole = secondEmoteOptional.get(); AssignableRole secondRole = secondEmoteOptional.get();
log.info("Swapping positions of emotes {} and {} in assignable role place {} in server {}: first: {} -> {}, second: {} -> {}",
firstRole.getEmote().getId(), secondRole.getEmote().getId(), place.getId(), server.getId(), firstRole.getPosition(), secondRole.getPosition(), secondRole.getPosition(), firstRole.getPosition());
int firstPosition = firstRole.getPosition(); int firstPosition = firstRole.getPosition();
firstRole.setPosition(secondRole.getPosition()); firstRole.setPosition(secondRole.getPosition());
secondRole.setPosition(firstPosition); secondRole.setPosition(firstPosition);
@@ -500,6 +541,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
public CompletableFuture<Void> testAssignableRolePlace(AServer server, String name, MessageChannel channel) { public CompletableFuture<Void> testAssignableRolePlace(AServer server, String name, MessageChannel channel) {
AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name);
MessageToSend messageToSend = renderAssignablePlacePosts(place); MessageToSend messageToSend = renderAssignablePlacePosts(place);
log.info("Testing assignable role place {} in channel {} on server {}.", place.getId(), channel.getId(), server.getId());
List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, channel); List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, channel);
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])); return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]));
} }
@@ -509,6 +551,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name);
List<AssignablePostConfigRole> roles = new ArrayList<>(); List<AssignablePostConfigRole> roles = new ArrayList<>();
Guild guild = botService.getGuildByIdNullable(server.getId()); Guild guild = botService.getGuildByIdNullable(server.getId());
log.info("Showing assignable role place config for place {} in channel {} on server {}.", place.getId(), channel.getId(), server.getId());
List<AssignableRole> assignableRoles = place.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList()); List<AssignableRole> assignableRoles = place.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList());
for (AssignableRole role : assignableRoles) { for (AssignableRole role : assignableRoles) {
AEmote emoteForRole = role.getEmote(); AEmote emoteForRole = role.getEmote();
@@ -521,6 +564,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
.position(role.getPosition()) .position(role.getPosition())
.awardedRole(jdaRole) .awardedRole(jdaRole)
.build(); .build();
log.trace("Displaying config for role {} with emote {} in position {}.", role.getId(), emoteForRole.getId(), role.getPosition());
roles.add(postRole); roles.add(postRole);
} }
AssignableRolePlaceConfig configModel = AssignableRolePlaceConfig AssignableRolePlaceConfig configModel = AssignableRolePlaceConfig
@@ -554,6 +598,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
@Override @Override
public CompletableFuture<Void> changeText(AServer server, String name, String newText) { public CompletableFuture<Void> changeText(AServer server, String name, String newText) {
AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name); AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name);
log.info("Changing text of assignable role place {} in server {}.", place.getId(), server.getId());
place.setText(newText); place.setText(newText);
return refreshTextFromPlace(place); return refreshTextFromPlace(place);
} }
@@ -562,10 +607,13 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
public CompletableFuture<Void> removeExistingReactionsAndRoles(AssignableRolePlace place, AssignedRoleUser user) { public CompletableFuture<Void> removeExistingReactionsAndRoles(AssignableRolePlace place, AssignedRoleUser user) {
Member memberInServer = botService.getMemberInServer(user.getUser()); Member memberInServer = botService.getMemberInServer(user.getUser());
List<CompletableFuture<Void>> futures = new ArrayList<>(); List<CompletableFuture<Void>> futures = new ArrayList<>();
log.info("Removing all existing reactions and roles by user {} on assignable role place {} in server {}.", user.getId(), place.getId(), user.getUser().getServerReference().getId());
user.getRoles().forEach(assignableRole -> { user.getRoles().forEach(assignableRole -> {
futures.add(roleService.removeAssignableRoleFromUser(assignableRole, memberInServer)); futures.add(roleService.removeAssignableRoleFromUser(assignableRole, memberInServer));
log.trace("Removing role {} from user {} in server {} because of assignable role clearing.", assignableRole.getRole().getId(), memberInServer.getId(), place.getServer().getId());
AEmote emoteToUseObject = emoteManagementService.loadEmote(assignableRole.getEmote().getId()); AEmote emoteToUseObject = emoteManagementService.loadEmote(assignableRole.getEmote().getId());
AssignableRolePlacePost assignablePlacePost = assignableRole.getAssignableRolePlacePost(); AssignableRolePlacePost assignablePlacePost = assignableRole.getAssignableRolePlacePost();
log.trace("Removing reaction with emote {} from user {} in server {} because of assignable role clearing.", emoteToUseObject.getId(), user.getUser().getUserReference().getId(), place.getServer().getId());
futures.add(messageService.removeReactionOfUserFromMessageWithFuture(emoteToUseObject, place.getServer().getId(), futures.add(messageService.removeReactionOfUserFromMessageWithFuture(emoteToUseObject, place.getServer().getId(),
assignablePlacePost.getUsedChannel().getId(), assignablePlacePost.getId(), memberInServer)); assignablePlacePost.getUsedChannel().getId(), assignablePlacePost.getId(), memberInServer));
}); });
@@ -599,6 +647,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
public CompletableFuture<Void> showAllAssignableRolePlaces(AServer server, MessageChannel channel) { public CompletableFuture<Void> showAllAssignableRolePlaces(AServer server, MessageChannel channel) {
List<AssignableRolePlace> assignableRolePlaces = rolePlaceManagementService.findAllByServer(server); List<AssignableRolePlace> assignableRolePlaces = rolePlaceManagementService.findAllByServer(server);
AssignablePlaceOverview overViewModel = AssignablePlaceOverview.builder().places(assignableRolePlaces).build(); AssignablePlaceOverview overViewModel = AssignablePlaceOverview.builder().places(assignableRolePlaces).build();
log.info("Showing overview over all assignable role places for server {} in channel {}.", server.getId(), channel.getId());
List<CompletableFuture<Message>> promises = channelService.sendEmbedTemplateInChannel(ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY, overViewModel, channel); List<CompletableFuture<Message>> promises = channelService.sendEmbedTemplateInChannel(ASSIGNABLE_ROLE_PLACES_OVERVIEW_TEMPLATE_KEY, overViewModel, channel);
return CompletableFuture.allOf(promises.toArray(new CompletableFuture[0])); return CompletableFuture.allOf(promises.toArray(new CompletableFuture[0]));
} }
@@ -608,6 +657,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
} }
private void deleteEmotesFromAssignableRolePlace(AssignableRolePlace place) { private void deleteEmotesFromAssignableRolePlace(AssignableRolePlace place) {
log.info("Deleting all emotes associated with assignable role place {} in server {}.", place.getId(), place.getServer().getId());
place.getAssignableRoles().forEach(role -> place.getAssignableRoles().forEach(role ->
emoteManagementService.deleteEmote(role.getEmote()) emoteManagementService.deleteEmote(role.getEmote())
); );
@@ -652,6 +702,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
current = rolesToAddIterator.next(); current = rolesToAddIterator.next();
} }
} else if(startOfNewMessage && lastAddedRole != null) { } else if(startOfNewMessage && lastAddedRole != null) {
log.trace("Forcing new message for post of assignable role place {}.", place.getId());
lastAddedRole.setForceNewMessage(true); lastAddedRole.setForceNewMessage(true);
} }
} }
@@ -665,29 +716,30 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
} }
@Transactional @Transactional
public CompletableFuture<Void> createAssignableRolePlacePosts(Long serverId, String name) { public CompletableFuture<Void> createAssignableRolePlacePosts(Long serverId, Long assignablePlaceId) {
AServer server = serverManagementService.loadOrCreate(serverId); AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByPlaceId(assignablePlaceId);
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, name);
Optional<TextChannel> channelOptional = botService.getTextChannelFromServerOptional(serverId, assignableRolePlace.getChannel().getId()); Optional<TextChannel> channelOptional = botService.getTextChannelFromServerOptional(serverId, assignableRolePlace.getChannel().getId());
if(channelOptional.isPresent()) { if(channelOptional.isPresent()) {
MessageChannel channel = channelOptional.get(); MessageChannel channel = channelOptional.get();
log.info("Sending assignable role place posts for place {} in channel {} in server {}.", assignableRolePlace.getId(), channel.getId(), serverId);
List<CompletableFuture<Message>> messageFutures = sendAssignablePostMessages(assignableRolePlace, channel); List<CompletableFuture<Message>> messageFutures = sendAssignablePostMessages(assignableRolePlace, channel);
return CompletableFuture.allOf(messageFutures.toArray(new CompletableFuture[0])) return CompletableFuture.allOf(messageFutures.toArray(new CompletableFuture[0]))
.thenCompose(aVoid -> self.addEmotes(messageFutures, name)); .thenCompose(aVoid -> self.addEmotes(messageFutures, assignablePlaceId));
} else { } else {
log.warn("Channel to create assignable role post in does not exist."); log.warn("Channel to create assignable role post in does not exist.");
throw new AssignableRolePlaceChannelDoesNotExist(assignableRolePlace.getChannel().getId(), name); throw new AssignableRolePlaceChannelDoesNotExist(assignableRolePlace.getChannel().getId(), assignableRolePlace.getKey());
} }
} }
@Transactional @Transactional
public CompletableFuture<Void> addEmotes(List<CompletableFuture<Message>> assignablePlacePostsMessageFutures, String placeKey) { public CompletableFuture<Void> addEmotes(List<CompletableFuture<Message>> assignablePlacePostsMessageFutures, Long assignablePlaceId) {
Message firstMessage = assignablePlacePostsMessageFutures.get(0).join(); Message firstMessage = assignablePlacePostsMessageFutures.get(0).join();
Long serverId = firstMessage.getGuild().getIdLong(); Long serverId = firstMessage.getGuild().getIdLong();
AServer innerServer = serverManagementService.loadOrCreate(serverId); AssignableRolePlace innerRolePlace = rolePlaceManagementService.findByPlaceId(assignablePlaceId);
AssignableRolePlace innerRolePlace = rolePlaceManagementService.findByServerAndKey(innerServer, placeKey); log.info("Adding emotes to assignable role place {}.", innerRolePlace);
log.trace("We have {} posts and {} roles.", assignablePlacePostsMessageFutures.size(), innerRolePlace.getAssignableRoles().size());
List<AssignableRole> roleStream = innerRolePlace.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList()); List<AssignableRole> roleStream = innerRolePlace.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList());
List<CompletableFuture<Void>> reactionFutures = new ArrayList<>(); List<CompletableFuture<Void>> reactionFutures = new ArrayList<>();
@@ -698,20 +750,21 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
MessageEmbed embed = sentMessage.getEmbeds().get(0); MessageEmbed embed = sentMessage.getEmbeds().get(0);
List<AssignableRole> firstRoles = roleStream.subList(usedEmotes, usedEmotes + embed.getFields().size()); List<AssignableRole> firstRoles = roleStream.subList(usedEmotes, usedEmotes + embed.getFields().size());
usedEmotes += embed.getFields().size(); usedEmotes += embed.getFields().size();
log.trace("Adding {} emotes to message {} for place {}. In total {} were added.", embed.getFields().size(), sentMessage.getId(), innerRolePlace.getId(), usedEmotes);
List<Integer> usedEmoteIds = firstRoles.stream().map(assignableRole -> assignableRole.getEmote().getId()).collect(Collectors.toList()); List<Integer> usedEmoteIds = firstRoles.stream().map(assignableRole -> assignableRole.getEmote().getId()).collect(Collectors.toList());
CompletableFuture<Void> firstMessageFuture = createAssignableRolePlacePost(sentMessage, serverId, usedEmoteIds); CompletableFuture<Void> firstMessageFuture = addingReactionsToAssignableRolePlacePost(sentMessage, serverId, usedEmoteIds);
reactionFutures.add(firstMessageFuture); reactionFutures.add(firstMessageFuture);
} }
return CompletableFuture.allOf(reactionFutures.toArray(new CompletableFuture[0])).thenCompose(aVoid -> { return CompletableFuture.allOf(reactionFutures.toArray(new CompletableFuture[0])).thenCompose(aVoid -> {
self.storeCreatedAssignableRolePlacePosts(placeKey, serverId, assignablePlacePostsMessageFutures); self.storeCreatedAssignableRolePlacePosts(assignablePlaceId, serverId, assignablePlacePostsMessageFutures);
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
}); });
} }
@Transactional @Transactional
public void storeCreatedAssignableRolePlacePosts(String name, Long serverId, List<CompletableFuture<Message>> futures) { public void storeCreatedAssignableRolePlacePosts(Long assignablePlaceId, Long serverId, List<CompletableFuture<Message>> futures) {
AServer server = serverManagementService.loadOrCreate(serverId); AssignableRolePlace updatedPlace = rolePlaceManagementService.findByPlaceId(assignablePlaceId);
AssignableRolePlace updatedPlace = rolePlaceManagementService.findByServerAndKey(server, name); log.info("Storing {} messages for assignable role place {} in server {}.", futures.size(), assignablePlaceId, serverId);
List<AssignableRole> rolesToAdd = updatedPlace.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList()); List<AssignableRole> rolesToAdd = updatedPlace.getAssignableRoles().stream().sorted(Comparator.comparingInt(AssignableRole::getPosition)).collect(Collectors.toList());
int usedEmotes = 0; int usedEmotes = 0;
for (int i = 0; i < futures.size(); i++) { for (int i = 0; i < futures.size(); i++) {
@@ -721,6 +774,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
Message sentMessage = messageCompletableFuture.get(); Message sentMessage = messageCompletableFuture.get();
// this uses the actual embed count as a limit, so this relies on fields to be used for description, if this changes, this needs to be changed // this uses the actual embed count as a limit, so this relies on fields to be used for description, if this changes, this needs to be changed
MessageEmbed embed = sentMessage.getEmbeds().get(0); MessageEmbed embed = sentMessage.getEmbeds().get(0);
log.trace("Storing post {} with {} fields.", message.getId(), embed.getFields().size());
List<AssignableRole> firstRoles = rolesToAdd.subList(usedEmotes, usedEmotes + embed.getFields().size()); List<AssignableRole> firstRoles = rolesToAdd.subList(usedEmotes, usedEmotes + embed.getFields().size());
usedEmotes += embed.getFields().size(); usedEmotes += embed.getFields().size();
AssignableRolePlacePost post = AssignableRolePlacePost AssignableRolePlacePost post = AssignableRolePlacePost
@@ -740,9 +794,10 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
} }
@Transactional @Transactional
public CompletableFuture<Void> createAssignableRolePlacePost(Message message, Long server, List<Integer> emotesToAdd) { public CompletableFuture<Void> addingReactionsToAssignableRolePlacePost(Message message, Long server, List<Integer> emotesToAdd) {
// TODO might need to guarantee the order // TODO might need to guarantee the order
List<CompletableFuture<Void>> futures = new ArrayList<>(); List<CompletableFuture<Void>> futures = new ArrayList<>();
log.info("Adding {} emotes to assignable role place post {} in server {}.", emotesToAdd.size(), message.getId(), server);
emotesToAdd.forEach(emotesToUse -> { emotesToAdd.forEach(emotesToUse -> {
AEmote emoteToUseObject = emoteManagementService.loadEmote(emotesToUse); AEmote emoteToUseObject = emoteManagementService.loadEmote(emotesToUse);
futures.add(messageService.addReactionToMessageWithFuture(emoteToUseObject, server, message)); futures.add(messageService.addReactionToMessageWithFuture(emoteToUseObject, server, message));

View File

@@ -9,6 +9,7 @@ import dev.sheldan.abstracto.assignableroles.service.management.AssignedRoleUser
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.RoleService; import dev.sheldan.abstracto.core.service.RoleService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -17,6 +18,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j
public class AssignableRoleServiceBean implements AssignableRoleService { public class AssignableRoleServiceBean implements AssignableRoleService {
@Autowired @Autowired
@@ -40,12 +42,15 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
@Override @Override
public CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, Member toAdd) { public CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, Member toAdd) {
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId); AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
log.info("Assigning role {} to member {} in server {}.", assignableRoleId, toAdd.getId(), toAdd.getGuild().getId());
return roleService.addRoleToMemberFuture(toAdd, role.getRole()); return roleService.addRoleToMemberFuture(toAdd, role.getRole());
} }
@Override @Override
public void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer userInAServer) { public void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer userInAServer) {
AssignedRoleUser user = assignedRoleUserManagementServiceBean.findByUserInServer(userInAServer); AssignedRoleUser user = assignedRoleUserManagementServiceBean.findByUserInServer(userInAServer);
log.info("Clearing all {} assignable roles in place {} for user {} in server {}.",
user.getRoles().size(), place.getId(), userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
user.getRoles().forEach(assignableRole -> { user.getRoles().forEach(assignableRole -> {
if(assignableRole.getAssignablePlace().equals(place)) { if(assignableRole.getAssignablePlace().equals(place)) {
assignableRole.getAssignedUsers().remove(user); assignableRole.getAssignedUsers().remove(user);
@@ -63,6 +68,7 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
@Override @Override
public CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, Member member) { public CompletableFuture<Void> removeAssignableRoleFromUser(AssignableRole assignableRole, Member member) {
log.info("Removing assignable role {} from user {} in server {}.", assignableRole.getId(), member.getId(), member.getGuild().getId());
return roleService.removeRoleFromMemberFuture(member, assignableRole.getRole()); return roleService.removeRoleFromMemberFuture(member, assignableRole.getRole());
} }
@@ -82,11 +88,15 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
@Override @Override
public void addRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) { public void addRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) {
log.info("Persisting storing adding assignable role {} to user {} in server {}.",
assignableRole.getId(), aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
assignedRoleUserManagementServiceBean.addAssignedRoleToUser(assignableRole, aUserInAServer); assignedRoleUserManagementServiceBean.addAssignedRoleToUser(assignableRole, aUserInAServer);
} }
@Override @Override
public void removeRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) { public void removeRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) {
log.info("Persisting storing removing assignable role {} to user {} in server {}.",
assignableRole.getId(), aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
assignedRoleUserManagementServiceBean.removeAssignedRoleFromUser(assignableRole, aUserInAServer); assignedRoleUserManagementServiceBean.removeAssignedRoleFromUser(assignableRole, aUserInAServer);
} }
@@ -94,7 +104,7 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
public void addRoleToUser(Long assignableRoleId, Member member) { public void addRoleToUser(Long assignableRoleId, Member member) {
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId); AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(member); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(member);
assignedRoleUserManagementServiceBean.addAssignedRoleToUser(role, aUserInAServer); addRoleToUser(role, aUserInAServer);
} }
@Transactional @Transactional
@@ -107,6 +117,6 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
public void removeRoleFromUser(Long assignableRoleId, Member member) { public void removeRoleFromUser(Long assignableRoleId, Member member) {
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId); AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(member); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(member);
assignedRoleUserManagementServiceBean.removeAssignedRoleFromUser(role, aUserInAServer); removeRoleFromUser(role, aUserInAServer);
} }
} }

View File

@@ -11,11 +11,13 @@ import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.service.EmoteService; import dev.sheldan.abstracto.core.service.EmoteService;
import dev.sheldan.abstracto.core.service.management.EmoteManagementService; import dev.sheldan.abstracto.core.service.management.EmoteManagementService;
import dev.sheldan.abstracto.core.service.management.RoleManagementService; import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.MessageReaction; import net.dv8tion.jda.api.entities.MessageReaction;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@Slf4j
public class AssignableRoleManagementServiceBean implements AssignableRoleManagementService { public class AssignableRoleManagementServiceBean implements AssignableRoleManagementService {
@Autowired @Autowired
@@ -53,6 +55,7 @@ public class AssignableRoleManagementServiceBean implements AssignableRoleManage
.assignableRolePlacePost(post) .assignableRolePlacePost(post)
.build(); .build();
place.getAssignableRoles().add(roleToAdd); place.getAssignableRoles().add(roleToAdd);
log.info("Adding role {} to assignable role place {}. There are now {} roles.", role.getId(), place.getId(), place.getAssignableRoles().size());
return roleToAdd; return roleToAdd;
} }

View File

@@ -5,6 +5,7 @@ import dev.sheldan.abstracto.assignableroles.models.database.AssignableRolePlace
import dev.sheldan.abstracto.assignableroles.repository.AssignableRolePlaceRepository; import dev.sheldan.abstracto.assignableroles.repository.AssignableRolePlaceRepository;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -12,6 +13,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component @Component
@Slf4j
public class AssignableRolePlaceManagementServiceBean implements AssignableRolePlaceManagementService { public class AssignableRolePlaceManagementServiceBean implements AssignableRolePlaceManagementService {
@Autowired @Autowired
@@ -27,6 +29,7 @@ public class AssignableRolePlaceManagementServiceBean implements AssignableRoleP
.key(name) .key(name)
.build(); .build();
repository.save(place); repository.save(place);
log.info("Creating assignable role place in channel {} on server {}.", channel.getId(), server.getId());
return place; return place;
} }
@@ -54,17 +57,21 @@ public class AssignableRolePlaceManagementServiceBean implements AssignableRoleP
@Override @Override
public void moveAssignableRolePlace(AServer server, String name, AChannel newChannel) { public void moveAssignableRolePlace(AServer server, String name, AChannel newChannel) {
AssignableRolePlace assignablePlaceToChange = findByServerAndKey(server, name); AssignableRolePlace assignablePlaceToChange = findByServerAndKey(server, name);
log.info("Moving assignable role place {} in server {} from channel {} to channel {}.",
assignablePlaceToChange.getId(), server.getId(), assignablePlaceToChange.getChannel().getId(), newChannel.getId());
assignablePlaceToChange.setChannel(newChannel); assignablePlaceToChange.setChannel(newChannel);
} }
@Override @Override
public void changeAssignableRolePlaceDescription(AServer server, String name, String newDescription) { public void changeAssignableRolePlaceDescription(AServer server, String name, String newDescription) {
AssignableRolePlace assignablePlaceToChange = findByServerAndKey(server, name); AssignableRolePlace assignablePlaceToChange = findByServerAndKey(server, name);
log.info("Changing description of assignable role place {} in server {}.", assignablePlaceToChange.getId(), server.getId());
assignablePlaceToChange.setText(newDescription); assignablePlaceToChange.setText(newDescription);
} }
@Override @Override
public void deleteAssignablePlace(AssignableRolePlace toDelete) { public void deleteAssignablePlace(AssignableRolePlace toDelete) {
log.info("Deleting assignable role place {} in server {} which was in server {}.", toDelete.getId(), toDelete.getChannel().getId(), toDelete.getServer().getId());
repository.delete(toDelete); repository.delete(toDelete);
} }

View File

@@ -5,12 +5,14 @@ import dev.sheldan.abstracto.assignableroles.models.database.AssignableRole;
import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser; import dev.sheldan.abstracto.assignableroles.models.database.AssignedRoleUser;
import dev.sheldan.abstracto.assignableroles.repository.AssignedRoleUserRepository; import dev.sheldan.abstracto.assignableroles.repository.AssignedRoleUserRepository;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Optional; import java.util.Optional;
@Component @Component
@Slf4j
public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserManagementService { public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserManagementService {
@Autowired @Autowired
@@ -19,6 +21,9 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Override @Override
public void addAssignedRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) { public void addAssignedRoleToUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) {
Optional<AssignedRoleUser> optional = findByUserInServerOptional(aUserInAServer); Optional<AssignedRoleUser> optional = findByUserInServerOptional(aUserInAServer);
log.info("Adding assignable role {} to user {} in server {} because of assignable role place {}.",
assignableRole.getId(), aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId(),
assignableRole.getAssignablePlace().getId());
AssignedRoleUser user = optional.orElseGet(() -> createAssignedRoleUser(aUserInAServer)); AssignedRoleUser user = optional.orElseGet(() -> createAssignedRoleUser(aUserInAServer));
assignableRole.getAssignedUsers().add(user); assignableRole.getAssignedUsers().add(user);
user.getRoles().add(assignableRole); user.getRoles().add(assignableRole);
@@ -26,6 +31,9 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Override @Override
public void removeAssignedRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) { public void removeAssignedRoleFromUser(AssignableRole assignableRole, AUserInAServer aUserInAServer) {
log.info("Removing assignable role {} from user {} in server {} in assignable role place {}.",
assignableRole.getId(), aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId(),
assignableRole.getAssignablePlace().getId());
AssignedRoleUser user = findByUserInServer(aUserInAServer); AssignedRoleUser user = findByUserInServer(aUserInAServer);
assignableRole.getAssignedUsers().remove(user); assignableRole.getAssignedUsers().remove(user);
user.getRoles().remove(assignableRole); user.getRoles().remove(assignableRole);
@@ -33,6 +41,7 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Override @Override
public AssignedRoleUser createAssignedRoleUser(AUserInAServer aUserInAServer) { public AssignedRoleUser createAssignedRoleUser(AUserInAServer aUserInAServer) {
log.info("Creating assigned role user for user {} in server {}.", aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
AssignedRoleUser newUser = AssignedRoleUser.builder().user(aUserInAServer).id(aUserInAServer.getUserInServerId()).build(); AssignedRoleUser newUser = AssignedRoleUser.builder().user(aUserInAServer).id(aUserInAServer.getUserInServerId()).build();
return repository.save(newUser); return repository.save(newUser);
} }
@@ -40,6 +49,7 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Override @Override
public void clearAllAssignedRolesOfUser(AUserInAServer userInAServer) { public void clearAllAssignedRolesOfUser(AUserInAServer userInAServer) {
AssignedRoleUser user = findByUserInServer(userInAServer); AssignedRoleUser user = findByUserInServer(userInAServer);
log.info("Clearing all assignable roles for user {} in server {}.", userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
user.getRoles().forEach(assignableRole -> user.getRoles().forEach(assignableRole ->
assignableRole.getAssignedUsers().remove(user) assignableRole.getAssignedUsers().remove(user)
); );

View File

@@ -18,7 +18,7 @@ public interface AssignableRolePlaceService {
boolean hasAssignableRolePlaceEmote(AServer server, String placeName, AEmote emote); boolean hasAssignableRolePlaceEmote(AServer server, String placeName, AEmote emote);
boolean hasAssignableRolePlaceEmote(AssignableRolePlace place, AEmote emote); boolean hasAssignableRolePlaceEmote(AssignableRolePlace place, AEmote emote);
boolean isPositionUsed(AServer server, String placeName, Integer position); boolean isPositionUsed(AServer server, String placeName, Integer position);
CompletableFuture<Void> setEmoteToPosition(AServer server, String placeName, FullEmote emote, Integer position); void setEmoteToPosition(AServer server, String placeName, FullEmote emote, Integer position);
CompletableFuture<Void> addRoleToAssignableRolePlace(AServer server, String placeName, ARole role, FullEmote emote, String description); CompletableFuture<Void> addRoleToAssignableRolePlace(AServer server, String placeName, ARole role, FullEmote emote, String description);
CompletableFuture<Void> removeRoleFromAssignableRolePlace(AServer server, String placeName, FullEmote emote); CompletableFuture<Void> removeRoleFromAssignableRolePlace(AServer server, String placeName, FullEmote emote);
CompletableFuture<Void> setupAssignableRolePlace(AServer server, String name); CompletableFuture<Void> setupAssignableRolePlace(AServer server, String name);

View File

@@ -59,6 +59,7 @@ public class LeaderBoardCommand extends AbstractConditionableCommand {
LeaderBoard leaderBoard = userExperienceService.findLeaderBoardData(commandContext.getUserInitiatedContext().getServer(), page); LeaderBoard leaderBoard = userExperienceService.findLeaderBoardData(commandContext.getUserInitiatedContext().getServer(), page);
LeaderBoardModel leaderBoardModel = (LeaderBoardModel) ContextConverter.fromCommandContext(commandContext, LeaderBoardModel.class); LeaderBoardModel leaderBoardModel = (LeaderBoardModel) ContextConverter.fromCommandContext(commandContext, LeaderBoardModel.class);
leaderBoardModel.setUserExperiences(converter.fromLeaderBoard(leaderBoard)); leaderBoardModel.setUserExperiences(converter.fromLeaderBoard(leaderBoard));
log.info("Rendering leaderboard for page {} in server {} for user {}.", page, commandContext.getAuthor().getId(), commandContext.getGuild().getId());
LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(commandContext.getUserInitiatedContext().getAUserInAServer()); LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(commandContext.getUserInitiatedContext().getAUserInAServer());
leaderBoardModel.setUserExecuting(converter.fromLeaderBoardEntry(userRank)); leaderBoardModel.setUserExecuting(converter.fromLeaderBoardEntry(userRank));

View File

@@ -19,6 +19,7 @@ import dev.sheldan.abstracto.experience.service.ExperienceLevelService;
import dev.sheldan.abstracto.experience.service.AUserExperienceService; import dev.sheldan.abstracto.experience.service.AUserExperienceService;
import dev.sheldan.abstracto.templating.model.MessageToSend; import dev.sheldan.abstracto.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -30,6 +31,7 @@ import java.util.concurrent.CompletableFuture;
* Command used to show an embed containing information about the experience amount, level and message count of a ember on a server * Command used to show an embed containing information about the experience amount, level and message count of a ember on a server
*/ */
@Component @Component
@Slf4j
public class Rank extends AbstractConditionableCommand { public class Rank extends AbstractConditionableCommand {
public static final String RANK_POST_EMBED_TEMPLATE = "rank_post"; public static final String RANK_POST_EMBED_TEMPLATE = "rank_post";
@@ -56,6 +58,7 @@ public class Rank extends AbstractConditionableCommand {
LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(commandContext.getUserInitiatedContext().getAUserInAServer()); LeaderBoardEntry userRank = userExperienceService.getRankOfUserInServer(commandContext.getUserInitiatedContext().getAUserInAServer());
rankModel.setRankUser(converter.fromLeaderBoardEntry(userRank)); rankModel.setRankUser(converter.fromLeaderBoardEntry(userRank));
AUserExperience experienceObj = userRank.getExperience(); AUserExperience experienceObj = userRank.getExperience();
log.info("Rendering rank for user {} in server {}.", commandContext.getAuthor().getId(), commandContext.getGuild().getId());
rankModel.setExperienceToNextLevel(experienceLevelService.calculateExperienceToNextLevel(experienceObj.getCurrentLevel().getLevel(), experienceObj.getExperience())); rankModel.setExperienceToNextLevel(experienceLevelService.calculateExperienceToNextLevel(experienceObj.getCurrentLevel().getLevel(), experienceObj.getExperience()));
MessageToSend messageToSend = templateService.renderEmbedTemplate(RANK_POST_EMBED_TEMPLATE, rankModel); MessageToSend messageToSend = templateService.renderEmbedTemplate(RANK_POST_EMBED_TEMPLATE, rankModel);
return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())) return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel()))

View File

@@ -5,6 +5,7 @@ import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.experience.models.LeaderBoard; import dev.sheldan.abstracto.experience.models.LeaderBoard;
import dev.sheldan.abstracto.experience.models.LeaderBoardEntry; import dev.sheldan.abstracto.experience.models.LeaderBoardEntry;
import dev.sheldan.abstracto.experience.models.templates.LeaderBoardEntryModel; import dev.sheldan.abstracto.experience.models.templates.LeaderBoardEntryModel;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -16,6 +17,7 @@ import java.util.List;
* Converter used to convert from {@link LeaderBoard} to a list of {@link LeaderBoardEntryModel} * Converter used to convert from {@link LeaderBoard} to a list of {@link LeaderBoardEntryModel}
*/ */
@Component @Component
@Slf4j
public class LeaderBoardModelConverter { public class LeaderBoardModelConverter {
@Autowired @Autowired
@@ -30,6 +32,7 @@ public class LeaderBoardModelConverter {
*/ */
public List<LeaderBoardEntryModel> fromLeaderBoard(LeaderBoard leaderBoard) { public List<LeaderBoardEntryModel> fromLeaderBoard(LeaderBoard leaderBoard) {
List<LeaderBoardEntryModel> models = new ArrayList<>(); List<LeaderBoardEntryModel> models = new ArrayList<>();
log.trace("Converting {} entries to a list of leaderbord entries.", leaderBoard.getEntries().size());
leaderBoard.getEntries().forEach(leaderBoardEntry -> { leaderBoard.getEntries().forEach(leaderBoardEntry -> {
LeaderBoardEntryModel entry = fromLeaderBoardEntry(leaderBoardEntry); LeaderBoardEntryModel entry = fromLeaderBoardEntry(leaderBoardEntry);
models.add(entry); models.add(entry);

View File

@@ -36,8 +36,9 @@ public class ExperiencePersistingJob extends QuartzJobBean {
log.info("Running experience persisting job."); log.info("Running experience persisting job.");
Long pastMinute = (Instant.now().getEpochSecond() / 60) - 1; Long pastMinute = (Instant.now().getEpochSecond() / 60) - 1;
if(runtimeExperience.containsKey(pastMinute)) { if(runtimeExperience.containsKey(pastMinute)) {
log.info("Found experience to persist."); List<ServerExperience> foundServers = runtimeExperience.get(pastMinute);
userExperienceService.handleExperienceGain(runtimeExperience.get(pastMinute)).thenAccept(aVoid -> log.info("Found experience from {} servers to persist.", foundServers.size());
userExperienceService.handleExperienceGain(foundServers).thenAccept(aVoid ->
runtimeExperience.remove(pastMinute) runtimeExperience.remove(pastMinute)
); );
} }

View File

@@ -34,8 +34,10 @@ public class JoiningUserRoleListener implements JoinListener {
if(userExperience != null) { if(userExperience != null) {
log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", member.getUser().getIdLong(), guild.getIdLong()); log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", member.getUser().getIdLong(), guild.getIdLong());
userExperienceService.syncForSingleUser(userExperience).thenAccept(result -> userExperienceService.syncForSingleUser(userExperience).thenAccept(result ->
log.trace("Finished re-assigning experience for re-joning user {} in server {}.", userInServerId, guild.getIdLong()) log.info("Finished re-assigning experience for re-joning user {} in server {}.", userInServerId, guild.getIdLong())
); );
} else {
log.info("Joined user {} in server {} does not have any previous experience. Not setting up anything.", member.getId(), guild.getId());
} }
} }

View File

@@ -32,7 +32,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -89,23 +88,27 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
*/ */
@Override @Override
public void addExperience(AUserInAServer userInAServer) { public void addExperience(AUserInAServer userInAServer) {
Long second = Instant.now().getEpochSecond() / 60; Long minute = Instant.now().getEpochSecond() / 60;
Map<Long, List<ServerExperience>> runtimeExperience = runTimeExperienceService.getRuntimeExperience(); Map<Long, List<ServerExperience>> runtimeExperience = runTimeExperienceService.getRuntimeExperience();
if(runtimeExperience.containsKey(second)) { if(runtimeExperience.containsKey(minute)) {
List<ServerExperience> existing = runtimeExperience.get(second); log.trace("Minute {} already tracked, adding user {} in server {}.",
existing.forEach(server -> { minute, userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
if(server.getUserInServerIds().stream().noneMatch(userInAServer1 -> userInAServer.getUserInServerId().equals(userInAServer1))) { List<ServerExperience> existing = runtimeExperience.get(minute);
for (ServerExperience server : existing) {
if (server.getServerId().equals(userInAServer.getServerReference().getId()) && server.getUserInServerIds().stream().noneMatch(userInAServer1 -> userInAServer.getUserInServerId().equals(userInAServer1))) {
server.getUserInServerIds().add(userInAServer.getUserInServerId()); server.getUserInServerIds().add(userInAServer.getUserInServerId());
break;
} }
}); }
} else { } else {
log.trace("Minute {} did not exist yet. Creating new entry for user {} in server {}.", minute, userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
ServerExperience serverExperience = ServerExperience ServerExperience serverExperience = ServerExperience
.builder() .builder()
.serverId(userInAServer.getServerReference().getId()) .serverId(userInAServer.getServerReference().getId())
.build(); .build();
serverExperience.getUserInServerIds().add(userInAServer.getUserInServerId()); serverExperience.getUserInServerIds().add(userInAServer.getUserInServerId());
runtimeExperience.put(second, new ArrayList<>(Arrays.asList(serverExperience))); runtimeExperience.put(minute, new ArrayList<>(Arrays.asList(serverExperience)));
} }
} }
@@ -128,11 +131,13 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
AExperienceLevel lastLevel = levels.get(0); AExperienceLevel lastLevel = levels.get(0);
for (AExperienceLevel level : levels) { for (AExperienceLevel level : levels) {
if(level.getExperienceNeeded() >= experienceCount) { if(level.getExperienceNeeded() >= experienceCount) {
log.trace("Calculated level {} for {} experience.", lastLevel.getLevel(), experienceCount);
return lastLevel; return lastLevel;
} else { } else {
lastLevel = level; lastLevel = level;
} }
} }
log.trace("Calculated level {} for {} experience.", lastLevel.getLevel(), experienceCount);
return lastLevel; return lastLevel;
} }
@@ -166,7 +171,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
// TODO what if there are a lot in here...., transaction size etc // TODO what if there are a lot in here...., transaction size etc
servers.forEach(serverExp -> { servers.forEach(serverExp -> {
AServer server = serverManagementService.loadOrCreate(serverExp.getServerId()); AServer server = serverManagementService.loadOrCreate(serverExp.getServerId());
log.trace("Handling experience for server {}", serverExp.getServerId()); log.info("Handling {} experience for server {}", serverExp.getUserInServerIds().size(), serverExp.getServerId());
int minExp = configService.getLongValue(ExperienceFeatureConfig.MIN_EXP_KEY, serverExp.getServerId()).intValue(); int minExp = configService.getLongValue(ExperienceFeatureConfig.MIN_EXP_KEY, serverExp.getServerId()).intValue();
int maxExp = configService.getLongValue(ExperienceFeatureConfig.MAX_EXP_KEY, serverExp.getServerId()).intValue(); int maxExp = configService.getLongValue(ExperienceFeatureConfig.MAX_EXP_KEY, serverExp.getServerId()).intValue();
Double multiplier = configService.getDoubleValue(ExperienceFeatureConfig.EXP_MULTIPLIER_KEY, serverExp.getServerId()); Double multiplier = configService.getDoubleValue(ExperienceFeatureConfig.EXP_MULTIPLIER_KEY, serverExp.getServerId());
@@ -206,7 +211,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
log.trace("Experience gain was disabled. User did not gain any experience."); log.trace("Experience gain was disabled. User did not gain any experience.");
} }
} else { } else {
log.info("user experience for user {} was not found. Planning to create new instance.", userInAServer.getUserInServerId()); log.info("User experience for user {} was not found. Planning to create new instance.", userInAServer.getUserInServerId());
Long newExperience = gainedExperience.longValue(); Long newExperience = gainedExperience.longValue();
AExperienceLevel newLevel = calculateLevel(levels, newExperience); AExperienceLevel newLevel = calculateLevel(levels, newExperience);
Long newMessageCount = 1L; Long newMessageCount = 1L;
@@ -246,6 +251,8 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
} }
AExperienceRole role = experienceRoleService.calculateRole(roles, currentLevel); AExperienceRole role = experienceRoleService.calculateRole(roles, currentLevel);
if(role == null) { if(role == null) {
log.trace("No experience role calculated. Applying none to user {} in server {}.",
aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
return CompletableFuture.completedFuture(RoleCalculationResult return CompletableFuture.completedFuture(RoleCalculationResult
.builder() .builder()
.userInServerId(aUserInAServer.getUserInServerId()) .userInServerId(aUserInAServer.getUserInServerId())
@@ -254,6 +261,8 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
} }
Long experienceRoleId = role.getId(); Long experienceRoleId = role.getId();
Long userInServerId = aUserInAServer.getUserInServerId(); Long userInServerId = aUserInAServer.getUserInServerId();
log.trace("Applying {} as the first experience role for user {} in server {}.",
experienceRoleId, aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
return roleService.addRoleToUserFuture(aUserInAServer, role.getRole()).thenApply(aVoid -> RoleCalculationResult return roleService.addRoleToUserFuture(aUserInAServer, role.getRole()).thenApply(aVoid -> RoleCalculationResult
.builder() .builder()
.experienceRoleId(experienceRoleId) .experienceRoleId(experienceRoleId)
@@ -264,6 +273,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
@Transactional @Transactional
public void persistExperienceChanges(List<ExperienceGainResult> resultFutures) { public void persistExperienceChanges(List<ExperienceGainResult> resultFutures) {
List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig(); List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig();
log.info("Storing {} experience gain results.", resultFutures.size());
HashMap<Long, List<AExperienceRole>> serverRoleMapping = new HashMap<>(); HashMap<Long, List<AExperienceRole>> serverRoleMapping = new HashMap<>();
resultFutures.forEach(experienceGainResult -> { resultFutures.forEach(experienceGainResult -> {
AUserInAServer user = userInServerManagementService.loadUser(experienceGainResult.getUserInServerId()); AUserInAServer user = userInServerManagementService.loadUser(experienceGainResult.getUserInServerId());
@@ -280,14 +290,14 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
if(foundLevel.isPresent()) { if(foundLevel.isPresent()) {
userExperience.setCurrentLevel(foundLevel.get()); userExperience.setCurrentLevel(foundLevel.get());
} else { } else {
log.warn("User {} was present, but no level could be found.", userExperience.getUser().getUserReference().getId()); log.warn("User {} was present, but no level matching the calculation result {} could be found.", userExperience.getUser().getUserReference().getId(), experienceGainResult.getNewLevel());
} }
AServer server = user.getServerReference(); AServer server = user.getServerReference();
if(!serverRoleMapping.containsKey(server.getId())) { if(!serverRoleMapping.containsKey(server.getId())) {
serverRoleMapping.put(server.getId(), experienceRoleManagementService.getExperienceRolesForServer(server)); serverRoleMapping.put(server.getId(), experienceRoleManagementService.getExperienceRolesForServer(server));
} }
List<AExperienceRole> roleConfig = serverRoleMapping.get(server.getId()); RoleCalculationResult roleCalculationResult = experienceGainResult.getCalculationResult().join();
AExperienceRole role = experienceRoleService.calculateRole(roleConfig, userExperience.getLevelOrDefault()); AExperienceRole role = experienceRoleManagementService.getExperienceRoleById(roleCalculationResult.getExperienceRoleId());
userExperience.setCurrentExperienceRole(role); userExperience.setCurrentExperienceRole(role);
if(experienceGainResult.isCreateUserExperience()) { if(experienceGainResult.isCreateUserExperience()) {
userExperienceManagementService.saveUser(userExperience); userExperienceManagementService.saveUser(userExperience);
@@ -321,6 +331,8 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
Member member = botService.getMemberInServer(user.getServerReference(), user.getUserReference()); Member member = botService.getMemberInServer(user.getServerReference(), user.getUserReference());
boolean currentlyHasNoExperienceRole = userExperience.getCurrentExperienceRole() == null; boolean currentlyHasNoExperienceRole = userExperience.getCurrentExperienceRole() == null;
if(role == null) { if(role == null) {
log.trace("User {} in server {} does not have an experience role, according to new calculation.",
user.getUserReference().getId(), user.getServerReference().getId());
if(!currentlyHasNoExperienceRole){ if(!currentlyHasNoExperienceRole){
return roleService.removeRoleFromUserFuture(user, userExperience.getCurrentExperienceRole().getRole()) return roleService.removeRoleFromUserFuture(user, userExperience.getCurrentExperienceRole().getRole())
.thenApply(returnNullRole); .thenApply(returnNullRole);
@@ -335,7 +347,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
.userInServerId(userInServerId) .userInServerId(userInServerId)
.build(); .build();
if(!userHasRoleAlready && (currentlyHasNoExperienceRole || !role.getRole().getId().equals(userExperience.getCurrentExperienceRole().getRole().getId()))) { if(!userHasRoleAlready && (currentlyHasNoExperienceRole || !role.getRole().getId().equals(userExperience.getCurrentExperienceRole().getRole().getId()))) {
log.info("User {} in server {} gets a new role {}", user.getUserReference().getId(), user.getServerReference().getId(), role.getRole().getId()); log.info("User {} in server {} gets a new role {} because of experience.", user.getUserReference().getId(), user.getServerReference().getId(), role.getRole().getId());
CompletableFuture<Void> removalFuture; CompletableFuture<Void> removalFuture;
if(!currentlyHasNoExperienceRole && botService.isUserInGuild(userExperience.getUser())) { if(!currentlyHasNoExperienceRole && botService.isUserInGuild(userExperience.getUser())) {
removalFuture = roleService.removeRoleFromUserFuture(user, userExperience.getCurrentExperienceRole().getRole()); removalFuture = roleService.removeRoleFromUserFuture(user, userExperience.getCurrentExperienceRole().getRole());
@@ -395,9 +407,11 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
AUserExperience userExperience = userExperienceManagementService.findUserInServer(user); AUserExperience userExperience = userExperienceManagementService.findUserInServer(user);
log.trace("Updating experience role for {} in server {} to {}", user.getUserInServerId(), user.getServerReference(), result.getExperienceRoleId()); log.trace("Updating experience role for {} in server {} to {}", user.getUserInServerId(), user.getServerReference(), result.getExperienceRoleId());
if(result.getExperienceRoleId() != null) { if(result.getExperienceRoleId() != null) {
log.trace("User experience {} gets new experience role with id {}.", userExperience.getId(), result.getExperienceRoleId());
AExperienceRole role = experienceRoleManagementService.getExperienceRoleById(result.getExperienceRoleId()); AExperienceRole role = experienceRoleManagementService.getExperienceRoleById(result.getExperienceRoleId());
userExperience.setCurrentExperienceRole(role); userExperience.setCurrentExperienceRole(role);
} else { } else {
log.trace("User experience {} does not get a user experience role.", userExperience.getId());
userExperience.setCurrentExperienceRole(null); userExperience.setCurrentExperienceRole(null);
} }
} }
@@ -414,30 +428,26 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
public CompletableFutureList<RoleCalculationResult> executeActionOnUserExperiencesWithFeedBack(List<AUserExperience> experiences, AChannel channel, Function<AUserExperience, CompletableFuture<RoleCalculationResult>> toExecute) { public CompletableFutureList<RoleCalculationResult> executeActionOnUserExperiencesWithFeedBack(List<AUserExperience> experiences, AChannel channel, Function<AUserExperience, CompletableFuture<RoleCalculationResult>> toExecute) {
List<CompletableFuture<RoleCalculationResult>> futures = new ArrayList<>(); List<CompletableFuture<RoleCalculationResult>> futures = new ArrayList<>();
MessageToSend status = getUserSyncStatusUpdateModel(0, experiences.size()); MessageToSend status = getUserSyncStatusUpdateModel(0, experiences.size());
try { Message statusMessage = messageService.createStatusMessage(status, channel).join();
Message statusMessage = messageService.createStatusMessage(status, channel).get(); int interval = Math.min(Math.max(experiences.size() / 10, 1), 100);
int interval = Math.min(Math.max(experiences.size() / 10, 1), 100); for (int i = 0; i < experiences.size(); i++) {
for (int i = 0; i < experiences.size(); i++) { if((i % interval) == 1) {
if((i % interval) == 1) { log.trace("Updating feedback message with new index {} out of {}", i, experiences.size());
log.trace("Updating feedback message with new index {} out of {}", i, experiences.size()); status = getUserSyncStatusUpdateModel(i, experiences.size());
status = getUserSyncStatusUpdateModel(i, experiences.size()); messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status);
messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status);
}
futures.add(toExecute.apply(experiences.get(i)));
log.trace("Synchronizing {} out of {}", i, experiences.size());
} }
status = getUserSyncStatusUpdateModel(experiences.size(), experiences.size()); futures.add(toExecute.apply(experiences.get(i)));
messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status); log.trace("Synchronizing {} out of {}", i, experiences.size());
} catch (InterruptedException | ExecutionException e) {
log.info("Failed to synchronize users.", e);
Thread.currentThread().interrupt();
} }
status = getUserSyncStatusUpdateModel(experiences.size(), experiences.size());
messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status);
return new CompletableFutureList<>(futures); return new CompletableFutureList<>(futures);
} }
@Override @Override
public void disableExperienceForUser(AUserInAServer userInAServer) { public void disableExperienceForUser(AUserInAServer userInAServer) {
log.info("Disabling experience gain for user {} in server {}.", userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer); AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer);
userExperience.setExperienceGainDisabled(true); userExperience.setExperienceGainDisabled(true);
} }
@@ -445,6 +455,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
@Override @Override
public void enableExperienceForUser(AUserInAServer userInAServer) { public void enableExperienceForUser(AUserInAServer userInAServer) {
AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer); AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer);
log.info("Enabling experience gain for user {} in server {}.", userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
userExperience.setExperienceGainDisabled(false); userExperience.setExperienceGainDisabled(false);
} }
@@ -478,8 +489,10 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
} }
page--; page--;
int pageSize = 10; int pageSize = 10;
log.trace("Loading leaderboard page {} for server {}.", page, server.getId());
List<AUserExperience> experiences = userExperienceManagementService.findLeaderBoardUsersPaginated(server, page * pageSize, (page + 1) * pageSize); List<AUserExperience> experiences = userExperienceManagementService.findLeaderBoardUsersPaginated(server, page * pageSize, (page + 1) * pageSize);
List<LeaderBoardEntry> entries = new ArrayList<>(); List<LeaderBoardEntry> entries = new ArrayList<>();
log.trace("Found {} experiences.", experiences.size());
for (int i = 0; i < experiences.size(); i++) { for (int i = 0; i < experiences.size(); i++) {
AUserExperience userExperience = experiences.get(i); AUserExperience userExperience = experiences.get(i);
entries.add(LeaderBoardEntry.builder().experience(userExperience).rank((page * pageSize) + i + 1).build()); entries.add(LeaderBoardEntry.builder().experience(userExperience).rank((page * pageSize) + i + 1).build());
@@ -494,7 +507,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
*/ */
@Override @Override
public LeaderBoardEntry getRankOfUserInServer(AUserInAServer userInAServer) { public LeaderBoardEntry getRankOfUserInServer(AUserInAServer userInAServer) {
log.info("Retrieving rank for {}", userInAServer.getUserReference().getId()); log.trace("Retrieving rank for {}", userInAServer.getUserReference().getId());
AUserExperience aUserExperience = userExperienceManagementService.findUserInServer(userInAServer); AUserExperience aUserExperience = userExperienceManagementService.findUserInServer(userInAServer);
Integer rank = 0; Integer rank = 0;
if(aUserExperience != null) { if(aUserExperience != null) {

View File

@@ -21,7 +21,7 @@ public class ExperienceLevelServiceBean implements ExperienceLevelService {
*/ */
private void createExperienceLevel(Integer level, Long experienceNeeded) { private void createExperienceLevel(Integer level, Long experienceNeeded) {
if(!experienceLevelManagementService.levelExists(level)) { if(!experienceLevelManagementService.levelExists(level)) {
log.trace("Creating new experience level {} with experience needed {}.", level, experienceNeeded); log.info("Creating new experience level {} with experience needed {}.", level, experienceNeeded);
experienceLevelManagementService.createExperienceLevel(level, experienceNeeded); experienceLevelManagementService.createExperienceLevel(level, experienceNeeded);
} }
} }
@@ -32,6 +32,7 @@ public class ExperienceLevelServiceBean implements ExperienceLevelService {
*/ */
@Override @Override
public void createLevelsUntil(Integer level) { public void createLevelsUntil(Integer level) {
log.info("Creating experience levels until level {}.", level);
createExperienceLevel(0, 0L); createExperienceLevel(0, 0L);
long experience = 0L; long experience = 0L;
for (int i = 1; i < level; i++) { for (int i = 1; i < level; i++) {

View File

@@ -59,6 +59,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Transactional @Transactional
public void unsetRoleInDb(Integer level, Long roleId) { public void unsetRoleInDb(Integer level, Long roleId) {
log.info("Unsetting role {} from level {}.", roleId, level);
AExperienceLevel experienceLevel = experienceLevelService.getLevel(level).orElseThrow(() -> new IllegalArgumentException(String.format("Could not find level %s", level))); AExperienceLevel experienceLevel = experienceLevelService.getLevel(level).orElseThrow(() -> new IllegalArgumentException(String.format("Could not find level %s", level)));
ARole loadedRole = roleManagementService.findRole(roleId); ARole loadedRole = roleManagementService.findRole(roleId);
experienceRoleManagementService.removeAllRoleAssignmentsForLevelInServer(experienceLevel, loadedRole.getServer()); experienceRoleManagementService.removeAllRoleAssignmentsForLevelInServer(experienceLevel, loadedRole.getServer());
@@ -87,6 +88,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
self.persistData(calculationResults, roleId) self.persistData(calculationResults, roleId)
); );
} else { } else {
log.info("Roles does not have any active users, no need to remove them.");
experienceRoleManagementService.unsetRole(roleInServer); experienceRoleManagementService.unsetRole(roleInServer);
return CompletableFuture.completedFuture(null); return CompletableFuture.completedFuture(null);
} }
@@ -98,6 +100,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Transactional @Transactional
public void persistData(CompletableFutureList<RoleCalculationResult> results, Long roleId) { public void persistData(CompletableFutureList<RoleCalculationResult> results, Long roleId) {
log.info("Persisting {} role calculation results after changing the role {}.", results.getFutures().size(), roleId);
AExperienceRole roleInServer = experienceRoleManagementService.getRoleInServer(roleId); AExperienceRole roleInServer = experienceRoleManagementService.getRoleInServer(roleId);
experienceRoleManagementService.unsetRole(roleInServer); experienceRoleManagementService.unsetRole(roleInServer);
userExperienceService.syncRolesInStorage(results.getObjects()); userExperienceService.syncRolesInStorage(results.getObjects());
@@ -115,6 +118,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
if(roles == null || roles.isEmpty()) { if(roles == null || roles.isEmpty()) {
return null; return null;
} }
log.trace("Calculating role for level {} in server {}. Using {} roles in our config.", currentLevel, roles.get(0).getRoleServer().getId(), roles.size());
AExperienceRole lastRole = null; AExperienceRole lastRole = null;
for (AExperienceRole experienceRole : roles) { for (AExperienceRole experienceRole : roles) {
if(currentLevel >= experienceRole.getLevel().getLevel()) { if(currentLevel >= experienceRole.getLevel().getLevel()) {
@@ -128,6 +132,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Override @Override
public AExperienceLevel getLevelOfNextRole(AExperienceLevel startLevel, AServer server) { public AExperienceLevel getLevelOfNextRole(AExperienceLevel startLevel, AServer server) {
log.trace("Calculating level of next role for level {} in server {}.", startLevel.getLevel(), server.getId());
List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server); List<AExperienceRole> roles = experienceRoleManagementService.getExperienceRolesForServer(server);
roles = roles.stream().filter(role -> role.getLevel().getLevel() > startLevel.getLevel()).collect(Collectors.toList()); roles = roles.stream().filter(role -> role.getLevel().getLevel() > startLevel.getLevel()).collect(Collectors.toList());
roles.sort(Comparator.comparing(role -> role.getLevel().getLevel())); roles.sort(Comparator.comparing(role -> role.getLevel().getLevel()));

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.service.SystemCondition;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService; import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import dev.sheldan.abstracto.experience.models.database.AUserExperience; import dev.sheldan.abstracto.experience.models.database.AUserExperience;
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService; import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -16,6 +17,7 @@ import java.util.HashMap;
import java.util.Optional; import java.util.Optional;
@Component @Component
@Slf4j
public class HasLevelCondition implements SystemCondition { public class HasLevelCondition implements SystemCondition {
public static final String USER_ID_VARIABLE = "userId"; public static final String USER_ID_VARIABLE = "userId";
@@ -29,15 +31,18 @@ public class HasLevelCondition implements SystemCondition {
@Override @Override
public boolean checkCondition(ConditionContextInstance conditionContext) { public boolean checkCondition(ConditionContextInstance conditionContext) {
HashMap<String, Object> parameters = conditionContext.getParameters(); HashMap<String, Object> parameters = conditionContext.getParameters();
Long userId = (Long) parameters.get(USER_ID_VARIABLE); Long userId = (Long) parameters.get(USER_ID_VARIABLE);
Integer level = (Integer) parameters.get(LEVEL_VARIABLE); Integer level = (Integer) parameters.get(LEVEL_VARIABLE);
log.info("Evaluating has level condition.");
Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserConditional(userId); Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserConditional(userId);
if(userInServerOptional.isPresent()) { if(userInServerOptional.isPresent()) {
AUserInAServer userInServer = userInServerOptional.get(); AUserInAServer userInServer = userInServerOptional.get();
log.info("Evaluating has level condition for user {} in server {} with level {}.",
userInServer.getUserReference().getId(), userInServer.getServerReference().getId(), level);
AUserExperience user = userExperienceManagementService.findUserInServer(userInServer); AUserExperience user = userExperienceManagementService.findUserInServer(userInServer);
return user.getCurrentLevel() != null && user.getCurrentLevel().getLevel() >= level; return user.getCurrentLevel() != null && user.getCurrentLevel().getLevel() >= level;
} }
log.info("No user experience object was found. Evaluating to false.");
return false; return false;
} }

View File

@@ -4,12 +4,14 @@ import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.experience.models.database.ADisabledExpRole; import dev.sheldan.abstracto.experience.models.database.ADisabledExpRole;
import dev.sheldan.abstracto.experience.repository.DisabledExpRoleRepository; import dev.sheldan.abstracto.experience.repository.DisabledExpRoleRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@Component @Component
@Slf4j
public class DisabledExpRoleManagementServiceBean implements DisabledExpRoleManagementService { public class DisabledExpRoleManagementServiceBean implements DisabledExpRoleManagementService {
@Autowired @Autowired
@@ -21,7 +23,7 @@ public class DisabledExpRoleManagementServiceBean implements DisabledExpRoleMana
.builder() .builder()
.role(role) .role(role)
.build(); .build();
log.info("Adding disabled exp role {} for server {}.", role.getId(),role.getServer().getId());
return disabledExpRoleRepository.save(newRole); return disabledExpRoleRepository.save(newRole);
} }

View File

@@ -9,7 +9,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component @Component
public class ExperienceLevelManagementServiceBean implements ExperienceLevelManagementService { public class ExperienceLevelManagementServiceBean implements ExperienceLevelManagementService {
@Autowired @Autowired
private ExperienceLevelRepository experienceLevelRepository; private ExperienceLevelRepository experienceLevelRepository;

View File

@@ -31,13 +31,14 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
*/ */
@Override @Override
public void removeAllRoleAssignmentsForLevelInServer(AExperienceLevel level, AServer server) { public void removeAllRoleAssignmentsForLevelInServer(AExperienceLevel level, AServer server) {
log.trace("Removing all role assignments for level {}.", level.getLevel());
List<AExperienceRole> existingExperienceRoles = experienceRoleRepository.findByLevelAndRoleServer(level, server); List<AExperienceRole> existingExperienceRoles = experienceRoleRepository.findByLevelAndRoleServer(level, server);
log.info("Removing all role assignments ({}) for level {} in server {}.", existingExperienceRoles.size(), level.getLevel(), server.getId());
existingExperienceRoles.forEach(existingRole -> experienceRoleRepository.delete(existingRole)); existingExperienceRoles.forEach(existingRole -> experienceRoleRepository.delete(existingRole));
} }
@Override @Override
public void unsetRole(AExperienceRole role) { public void unsetRole(AExperienceRole role) {
log.info("Deleting experience role {} in server {}.", role.getId(), role.getRoleServer().getId());
experienceRoleRepository.delete(role); experienceRoleRepository.delete(role);
} }
@@ -82,7 +83,9 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
public AExperienceRole setLevelToRole(AExperienceLevel level, ARole role) { public AExperienceRole setLevelToRole(AExperienceLevel level, ARole role) {
Optional<AExperienceRole> byRoleServerAndRoleOptional = getRoleInServerOptional(role); Optional<AExperienceRole> byRoleServerAndRoleOptional = getRoleInServerOptional(role);
AExperienceRole experienceRole; AExperienceRole experienceRole;
log.info("Setting role {} in server {} to level {}.", role.getId(), role.getServer().getId(), level);
if(byRoleServerAndRoleOptional.isPresent()) { if(byRoleServerAndRoleOptional.isPresent()) {
log.trace("Role already existed. Updating.");
experienceRole = byRoleServerAndRoleOptional.get(); experienceRole = byRoleServerAndRoleOptional.get();
experienceRole.setLevel(level); experienceRole.setLevel(level);
} else { } else {
@@ -92,6 +95,7 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
.roleServer(role.getServer()) .roleServer(role.getServer())
.role(role) .role(role)
.build(); .build();
log.trace("Role did not exist. Creating new.");
experienceRole = experienceRoleRepository.save(experienceRole); experienceRole = experienceRoleRepository.save(experienceRole);
} }
return experienceRole; return experienceRole;

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.experience.models.database.LeaderBoardEntryResult;
import dev.sheldan.abstracto.experience.models.database.AExperienceLevel; import dev.sheldan.abstracto.experience.models.database.AExperienceLevel;
import dev.sheldan.abstracto.experience.models.database.AUserExperience; import dev.sheldan.abstracto.experience.models.database.AUserExperience;
import dev.sheldan.abstracto.experience.repository.UserExperienceRepository; import dev.sheldan.abstracto.experience.repository.UserExperienceRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -15,7 +16,7 @@ import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@Slf4j
@Component @Component
public class UserExperienceManagementServiceBean implements UserExperienceManagementService { public class UserExperienceManagementServiceBean implements UserExperienceManagementService {
@@ -48,6 +49,7 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage
*/ */
@Override @Override
public AUserExperience createUserInServer(AUserInAServer aUserInAServer) { public AUserExperience createUserInServer(AUserInAServer aUserInAServer) {
log.info("Creating user experience for user {} in server {}.", aUserInAServer.getUserReference().getId(),aUserInAServer.getServerReference().getId());
AExperienceLevel startingLevel = experienceLevelManagementService.getLevel(0).orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", 0))); AExperienceLevel startingLevel = experienceLevelManagementService.getLevel(0).orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", 0)));
return AUserExperience return AUserExperience
.builder() .builder()
@@ -65,37 +67,6 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage
return repository.findByUser_ServerReference(server); return repository.findByUser_ServerReference(server);
} }
/**
* Creates or updates the {@link AUserExperience} object. Does not change the level or the role.
* @param user The {@link AUserInAServer} to increase the experience for
* @param experience The experience amount to increase by
* @param messageCount The amount of messages to increase the count by
* @return The created/changed {@link AUserExperience} object
*/
@Override
public AUserExperience incrementExpForUser(AUserInAServer user, Long experience, Long messageCount) {
Optional<AUserExperience> byId = repository.findById(user.getUserInServerId());
if(byId.isPresent()) {
AUserExperience userExperience = byId.get();
if(Boolean.FALSE.equals(userExperience.getExperienceGainDisabled())) {
userExperience.setMessageCount(userExperience.getMessageCount() + messageCount);
userExperience.setExperience(userExperience.getExperience() + experience);
}
return userExperience;
} else {
AExperienceLevel startingLevel = experienceLevelManagementService.getLevel(0).orElseThrow(() -> new AbstractoRunTimeException(String.format("Could not find level %s", 0)));
return AUserExperience
.builder()
.experience(experience)
.messageCount(messageCount)
.experienceGainDisabled(false)
.user(user)
.id(user.getUserInServerId())
.currentLevel(startingLevel)
.build();
}
}
@Override @Override
public List<AUserExperience> findLeaderBoardUsersPaginated(AServer aServer, Integer start, Integer end) { public List<AUserExperience> findLeaderBoardUsersPaginated(AServer aServer, Integer start, Integer end) {
return repository.findTop10ByUser_ServerReferenceOrderByExperienceDesc(aServer, PageRequest.of(start, end)); return repository.findTop10ByUser_ServerReferenceOrderByExperienceDesc(aServer, PageRequest.of(start, end));

View File

@@ -13,7 +13,6 @@ import dev.sheldan.abstracto.experience.models.database.AExperienceRole;
import dev.sheldan.abstracto.experience.models.database.AUserExperience; import dev.sheldan.abstracto.experience.models.database.AUserExperience;
import dev.sheldan.abstracto.experience.service.management.ExperienceLevelManagementService; import dev.sheldan.abstracto.experience.service.management.ExperienceLevelManagementService;
import dev.sheldan.abstracto.experience.service.management.ExperienceRoleManagementService; import dev.sheldan.abstracto.experience.service.management.ExperienceRoleManagementService;
import dev.sheldan.abstracto.test.MockUtils;
import net.dv8tion.jda.api.entities.Role; import net.dv8tion.jda.api.entities.Role;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@@ -52,10 +51,12 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Mock @Mock
private ExperienceRoleServiceBean self; private ExperienceRoleServiceBean self;
@Mock
private AServer server;
@Test @Test
public void testSettingRoleToLevelWithoutOldUsers() { public void testSettingRoleToLevelWithoutOldUsers() {
AServer server = MockUtils.getServer();
Integer levelCount = 10; Integer levelCount = 10;
AExperienceLevel level = AExperienceLevel.builder().experienceNeeded(10L).level(levelCount).build(); AExperienceLevel level = AExperienceLevel.builder().experienceNeeded(10L).level(levelCount).build();
Role roleToChange = Mockito.mock(Role.class); Role roleToChange = Mockito.mock(Role.class);
@@ -73,7 +74,6 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Test @Test
public void testUnsetRoleInDb() { public void testUnsetRoleInDb() {
AServer server = MockUtils.getServer();
Integer levelCount = 10; Integer levelCount = 10;
AExperienceLevel level = AExperienceLevel.builder().experienceNeeded(10L).level(levelCount).build(); AExperienceLevel level = AExperienceLevel.builder().experienceNeeded(10L).level(levelCount).build();
ARole roleToChange = getRole(1L, server); ARole roleToChange = getRole(1L, server);
@@ -89,7 +89,6 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Test @Test
public void testSettingRoleToLevelExistingUsers() { public void testSettingRoleToLevelExistingUsers() {
AServer server = MockUtils.getServer();
Integer levelCount = 10; Integer levelCount = 10;
AExperienceLevel level = AExperienceLevel.builder().experienceNeeded(10L).level(levelCount).build(); AExperienceLevel level = AExperienceLevel.builder().experienceNeeded(10L).level(levelCount).build();
Role roleToChange = Mockito.mock(Role.class); Role roleToChange = Mockito.mock(Role.class);
@@ -158,7 +157,6 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Test @Test
public void testCalculatingLevelOfNextRole() { public void testCalculatingLevelOfNextRole() {
AServer server = MockUtils.getServer();
when(experienceRoleManagementService.getExperienceRolesForServer(server)).thenReturn(getExperienceRoles()); when(experienceRoleManagementService.getExperienceRolesForServer(server)).thenReturn(getExperienceRoles());
AExperienceLevel levelToCheckFor = AExperienceLevel.builder().level(7).build(); AExperienceLevel levelToCheckFor = AExperienceLevel.builder().level(7).build();
AExperienceLevel levelOfNextRole = testingUnit.getLevelOfNextRole(levelToCheckFor, server); AExperienceLevel levelOfNextRole = testingUnit.getLevelOfNextRole(levelToCheckFor, server);
@@ -167,7 +165,6 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Test @Test
public void testCalculatingLevelOfNextRoleIfThereIsNone() { public void testCalculatingLevelOfNextRoleIfThereIsNone() {
AServer server = MockUtils.getServer();
when(experienceRoleManagementService.getExperienceRolesForServer(server)).thenReturn(getExperienceRoles()); when(experienceRoleManagementService.getExperienceRolesForServer(server)).thenReturn(getExperienceRoles());
AExperienceLevel levelToCheckFor = AExperienceLevel.builder().level(15).build(); AExperienceLevel levelToCheckFor = AExperienceLevel.builder().level(15).build();
AExperienceLevel levelOfNextRole = testingUnit.getLevelOfNextRole(levelToCheckFor, server); AExperienceLevel levelOfNextRole = testingUnit.getLevelOfNextRole(levelToCheckFor, server);
@@ -182,7 +179,7 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
private AExperienceRole getExperienceRoleForLevel(int levelToBuild) { private AExperienceRole getExperienceRoleForLevel(int levelToBuild) {
AExperienceLevel firstLevel = AExperienceLevel.builder().level(levelToBuild).build(); AExperienceLevel firstLevel = AExperienceLevel.builder().level(levelToBuild).build();
return AExperienceRole.builder().level(firstLevel).build(); return AExperienceRole.builder().roleServer(server).level(firstLevel).build();
} }
private ARole getRole(Long id, AServer server) { private ARole getRole(Long id, AServer server) {

View File

@@ -61,6 +61,7 @@ public class DisabledExpRoleManagementServiceBeanTest extends ExperienceRelatedT
} }
private ARole getARole() { private ARole getARole() {
return ARole.builder().id(1L).build(); AServer server = AServer.builder().id(4L).build();
return ARole.builder().id(1L).server(server).build();
} }
} }

View File

@@ -132,7 +132,9 @@ public class ExperienceRoleManagementServiceBeanTest extends ExperienceRelatedTe
private AExperienceRole getExperienceRoleForLevel(int levelToBuild) { private AExperienceRole getExperienceRoleForLevel(int levelToBuild) {
AExperienceLevel firstLevel = AExperienceLevel.builder().level(levelToBuild).build(); AExperienceLevel firstLevel = AExperienceLevel.builder().level(levelToBuild).build();
return AExperienceRole.builder().role(ARole.builder().id((long) levelToBuild).build()).level(firstLevel).build(); AServer server = AServer.builder().id(4L).build();
ARole aRole = ARole.builder().id((long) levelToBuild).server(server).build();
return AExperienceRole.builder().role(aRole).roleServer(server).level(firstLevel).build();
} }
private AExperienceLevel getLevel(Integer level, Long neededExperience) { private AExperienceLevel getLevel(Integer level, Long neededExperience) {

View File

@@ -15,6 +15,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
@@ -47,7 +48,13 @@ public class UserExperienceManagementServiceBeanTest extends ExperienceRelatedTe
@Test @Test
public void testNoUserCreateNewWhenSearching() { public void testNoUserCreateNewWhenSearching() {
AUserInAServer user = AUserInAServer.builder().userInServerId(1L).userReference(AUser.builder().id(2L).build()).build(); AUserInAServer user = Mockito.mock(AUserInAServer.class);
AServer server = Mockito.mock(AServer.class);
when(user.getServerReference()).thenReturn(server);
when(server.getId()).thenReturn(2L);
AUser aUser = Mockito.mock(AUser.class);
when(aUser.getId()).thenReturn(4L);
when(user.getUserReference()).thenReturn(aUser);
when(repository.findById(user.getUserInServerId())).thenReturn(Optional.empty()); when(repository.findById(user.getUserInServerId())).thenReturn(Optional.empty());
AExperienceLevel startLevel = mockInitialLevel(); AExperienceLevel startLevel = mockInitialLevel();
AUserExperience userInServer = testUnit.findUserInServer(user); AUserExperience userInServer = testUnit.findUserInServer(user);
@@ -59,7 +66,13 @@ public class UserExperienceManagementServiceBeanTest extends ExperienceRelatedTe
@Test @Test
public void testCreatingUserExperience() { public void testCreatingUserExperience() {
AUserInAServer user = AUserInAServer.builder().userInServerId(1L).userReference(AUser.builder().id(2L).build()).build(); AUserInAServer user = Mockito.mock(AUserInAServer.class);
AServer server = Mockito.mock(AServer.class);
when(user.getServerReference()).thenReturn(server);
when(server.getId()).thenReturn(2L);
AUser aUser = Mockito.mock(AUser.class);
when(aUser.getId()).thenReturn(4L);
when(user.getUserReference()).thenReturn(aUser);
AExperienceLevel startLevel = mockInitialLevel(); AExperienceLevel startLevel = mockInitialLevel();
AUserExperience userInServer = testUnit.createUserInServer(user); AUserExperience userInServer = testUnit.createUserInServer(user);
Assert.assertEquals(0L, userInServer.getExperience().longValue()); Assert.assertEquals(0L, userInServer.getExperience().longValue());
@@ -109,28 +122,6 @@ public class UserExperienceManagementServiceBeanTest extends ExperienceRelatedTe
Assert.assertEquals(experienceValue, rankOfUserInServer.getExperience().longValue()); Assert.assertEquals(experienceValue, rankOfUserInServer.getExperience().longValue());
} }
@Test
public void testIncrementExpForUser() {
executeTestForExperienceGain(false);
}
@Test
public void testIncrementExpForUserWithDisabledExp() {
executeTestForExperienceGain(true);
}
@Test
public void testIncrementForNonExistingUser() {
long addedExperience = 15L;
long addedMessages = 1L;
AUserInAServer user = AUserInAServer.builder().userInServerId(1L).userReference(AUser.builder().id(2L).build()).build();
when(repository.findById(user.getUserInServerId())).thenReturn(Optional.empty());
mockInitialLevel();
AUserExperience userExperience = testUnit.incrementExpForUser(user, addedExperience, addedMessages);
Assert.assertEquals(addedExperience, userExperience.getExperience().longValue());
Assert.assertEquals(addedMessages, userExperience.getMessageCount().longValue());
}
@Test @Test
public void testSaveUser() { public void testSaveUser() {
AUserInAServer user = AUserInAServer.builder().userInServerId(1L).userReference(AUser.builder().id(2L).build()).build(); AUserInAServer user = AUserInAServer.builder().userInServerId(1L).userReference(AUser.builder().id(2L).build()).build();
@@ -147,28 +138,6 @@ public class UserExperienceManagementServiceBeanTest extends ExperienceRelatedTe
return startLevel; return startLevel;
} }
private void executeTestForExperienceGain(boolean experienceGainDisabled) {
long oldExperience = 20L;
long oldMessageCount = 25L;
long addedExperience = 15L;
long addedMessages = 1L;
AUserInAServer user = AUserInAServer.builder().userInServerId(1L).userReference(AUser.builder().id(2L).build()).build();
AUserExperience experience = AUserExperience.builder().user(user).experienceGainDisabled(experienceGainDisabled).experience(oldExperience).messageCount(oldMessageCount).id(3L).build();
when(repository.findById(user.getUserInServerId())).thenReturn(Optional.of(experience));
AUserExperience userExperience = testUnit.incrementExpForUser(user, addedExperience, addedMessages);
long wantedExperience;
long wantedMessageCount;
if(experienceGainDisabled) {
wantedExperience = oldExperience;
wantedMessageCount = oldMessageCount;
} else {
wantedExperience = oldExperience + addedExperience;
wantedMessageCount = oldMessageCount + addedMessages;
}
Assert.assertEquals(wantedExperience, userExperience.getExperience().longValue());
Assert.assertEquals(wantedMessageCount, userExperience.getMessageCount().longValue());
}
private List<AUserExperience> getUserExperiences() { private List<AUserExperience> getUserExperiences() {
AUserExperience experience = AUserExperience.builder().experience(2L).build(); AUserExperience experience = AUserExperience.builder().experience(2L).build();
AUserExperience experience2 = AUserExperience.builder().experience(2L).build(); AUserExperience experience2 = AUserExperience.builder().experience(2L).build();

View File

@@ -37,17 +37,6 @@ public interface UserExperienceManagementService {
*/ */
List<AUserExperience> loadAllUsers(AServer server); List<AUserExperience> loadAllUsers(AServer server);
/**
* Increments the experience of the {@link AUserInAServer} by the given experience and the message count.
* {@link dev.sheldan.abstracto.experience.models.database.AExperienceLevel} or {@link dev.sheldan.abstracto.experience.models.database.AExperienceRole}
* are not changed.
* @param user The {@link AUserInAServer} to increase the experience for
* @param experience The experience amount to increase by
* @param messageCount The amount of messages to increase the count by
* @return The changed/creates {@link AUserExperience} object containing the values.
*/
AUserExperience incrementExpForUser(AUserInAServer user, Long experience, Long messageCount);
/** /**
* Retrieves a list of {@link AUserExperience} ordered by {@link AUserExperience.experience} and only returns the positions between {@code start} and @{code end}. * Retrieves a list of {@link AUserExperience} ordered by {@link AUserExperience.experience} and only returns the positions between {@code start} and @{code end}.
* @param server The {@link AServer} to retrieve the users for * @param server The {@link AServer} to retrieve the users for

View File

@@ -30,12 +30,14 @@ public class DeleteNote extends AbstractConditionableCommand {
@Autowired @Autowired
private TemplateService templateService; private TemplateService templateService;
@Override @Override
public CommandResult execute(CommandContext commandContext) { public CommandResult execute(CommandContext commandContext) {
checkParameters(commandContext); checkParameters(commandContext);
Long id = (Long) commandContext.getParameters().getParameters().get(0); Long id = (Long) commandContext.getParameters().getParameters().get(0);
if(userNoteManagementService.noteExists(id)) { if(userNoteManagementService.noteExists(id, commandContext.getUserInitiatedContext().getServer())) {
userNoteManagementService.deleteNote(id); userNoteManagementService.deleteNote(id, commandContext.getUserInitiatedContext().getServer());
} else { } else {
// TODO replace with exception // TODO replace with exception
return CommandResult.fromError(templateService.renderSimpleTemplate(NOTE_NOT_FOUND_EXCEPTION_TEMPLATE)); return CommandResult.fromError(templateService.renderSimpleTemplate(NOTE_NOT_FOUND_EXCEPTION_TEMPLATE));

View File

@@ -28,7 +28,7 @@ public class UnMuteJob extends QuartzJobBean {
@Override @Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException { protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
log.info("Executing unMute job for mute {}", muteId); log.info("Executing unMute job for mute {} in server {}", muteId, serverId);
muteService.endMute(muteId, serverId); muteService.endMute(muteId, serverId);
} }

View File

@@ -39,9 +39,11 @@ public class WarnDecayJob extends QuartzJobBean {
@Transactional @Transactional
public void executeInternal(JobExecutionContext context) throws JobExecutionException { public void executeInternal(JobExecutionContext context) throws JobExecutionException {
List<AServer> allServers = serverManagementService.getAllServers(); List<AServer> allServers = serverManagementService.getAllServers();
log.info("Executing warn decay job.");
allServers.forEach(server -> { allServers.forEach(server -> {
boolean featureEnabled = featureFlagService.isFeatureEnabled(warningDecayFeature, server); boolean featureEnabled = featureFlagService.isFeatureEnabled(warningDecayFeature, server);
if(featureEnabled) { if(featureEnabled) {
log.info("Executing warn decay for server {}.", server.getId());
warnService.decayWarningsForServer(server); warnService.decayWarningsForServer(server);
} }
}); });

View File

@@ -50,6 +50,7 @@ public class MessageDeleteLogListener implements MessageDeletedListener {
MessageToSend message = templateService.renderEmbedTemplate(MESSAGE_DELETED_TEMPLATE, logModel); MessageToSend message = templateService.renderEmbedTemplate(MESSAGE_DELETED_TEMPLATE, logModel);
postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId()); postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId());
if(messageFromCache.getAttachmentUrls() != null){ if(messageFromCache.getAttachmentUrls() != null){
log.trace("Notifying about deletions of {} attachments.", messageFromCache.getAttachmentUrls().size());
for (int i = 0; i < messageFromCache.getAttachmentUrls().size(); i++) { for (int i = 0; i < messageFromCache.getAttachmentUrls().size(); i++) {
MessageDeletedAttachmentLog log = MessageDeletedAttachmentLog MessageDeletedAttachmentLog log = MessageDeletedAttachmentLog
.builder() .builder()

View File

@@ -5,11 +5,13 @@ import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService; import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService; import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;
import dev.sheldan.abstracto.moderation.config.features.WarningDecayFeature; import dev.sheldan.abstracto.moderation.config.features.WarningDecayFeature;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@Slf4j
public class WarnDecayConfigListener implements ServerConfigListener { public class WarnDecayConfigListener implements ServerConfigListener {
@Autowired @Autowired
@@ -20,6 +22,7 @@ public class WarnDecayConfigListener implements ServerConfigListener {
@Override @Override
public void updateServerConfig(AServer server) { public void updateServerConfig(AServer server) {
log.info("Updating decay day configuration for server {}.", server.getId());
configManagementService.createIfNotExists(server.getId(), WarningDecayFeature.DECAY_DAYS_KEY, defaultConfigManagementService.getDefaultConfig(WarningDecayFeature.DECAY_DAYS_KEY).getLongValue()); configManagementService.createIfNotExists(server.getId(), WarningDecayFeature.DECAY_DAYS_KEY, defaultConfigManagementService.getDefaultConfig(WarningDecayFeature.DECAY_DAYS_KEY).getLongValue());
} }
} }

View File

@@ -19,8 +19,9 @@ public interface UserNoteRepository extends JpaRepository<UserNote, Long> {
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
List<UserNote> findByUser_ServerReference(AServer server); List<UserNote> findByUser_ServerReference(AServer server);
@Override
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
boolean existsById(@NonNull Long aLong); boolean existsByUserNoteId_IdAndUserNoteId_ServerId(@NonNull Long aLong, Long serverId);
void deleteByUserNoteId_IdAndUserNoteId_ServerId(@NonNull Long aLong, Long serverId);
} }

View File

@@ -54,7 +54,6 @@ public class BanServiceBean implements BanService {
private CompletableFuture<Void> banUser(Long guildId, Long userId, String reason) { private CompletableFuture<Void> banUser(Long guildId, Long userId, String reason) {
Optional<Guild> guildByIdOptional = botService.getGuildById(guildId); Optional<Guild> guildByIdOptional = botService.getGuildById(guildId);
if(guildByIdOptional.isPresent()) { if(guildByIdOptional.isPresent()) {
log.info("Banning user {} in guild {}.", userId, guildId);
return banUser(guildByIdOptional.get(), userId, reason); return banUser(guildByIdOptional.get(), userId, reason);
} else { } else {
log.warn("Guild {} not found. Not able to ban user {}", guildId, userId); log.warn("Guild {} not found. Not able to ban user {}", guildId, userId);
@@ -63,6 +62,7 @@ public class BanServiceBean implements BanService {
} }
private CompletableFuture<Void> banUser(Guild guild, Long userId, String reason) { private CompletableFuture<Void> banUser(Guild guild, Long userId, String reason) {
log.info("Banning user {} in guild {}.", userId, guild.getId());
return guild.ban(userId.toString(), 0, reason).submit(); return guild.ban(userId.toString(), 0, reason).submit();
} }
} }

View File

@@ -134,12 +134,12 @@ public class MuteServiceBean implements MuteService {
throw new MuteRoleNotSetupException(); throw new MuteRoleNotSetupException();
} }
Member memberBeingMuted = userBeingMuted.getMember(); Member memberBeingMuted = userBeingMuted.getMember();
log.info("User {} mutes user {} until {}", log.info("User {} mutes user {} in server {} until {}",
memberBeingMuted.getIdLong(), userMuting.getMember().getIdLong(), unMuteDate); memberBeingMuted.getIdLong(), message.getServerId(), userMuting.getMember().getIdLong(), unMuteDate);
if(message.getMessageId() != null) { if(message.getMessageId() != null) {
log.trace("because of message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId()); log.info("because of message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId());
} else { } else {
log.trace("This mute was not triggered by a message."); log.info("This mute was not triggered by a message.");
} }
List<CompletableFuture<Void>> futures = new ArrayList<>(); List<CompletableFuture<Void>> futures = new ArrayList<>();
AUserInAServer userInServerBeingMuted = userBeingMuted.getAUserInAServer(); AUserInAServer userInServerBeingMuted = userBeingMuted.getAUserInAServer();
@@ -159,15 +159,16 @@ public class MuteServiceBean implements MuteService {
} }
private CompletableFuture<Void> sendMuteNotification(ServerChannelMessage message, Member memberBeingMuted, MuteNotification muteNotification) { private CompletableFuture<Void> sendMuteNotification(ServerChannelMessage message, Member memberBeingMuted, MuteNotification muteNotification) {
log.trace("Notifying the user about the mute."); log.info("Notifying the user about the mute.");
CompletableFuture<Void> notificationFuture = new CompletableFuture<>(); CompletableFuture<Void> notificationFuture = new CompletableFuture<>();
String muteNotificationMessage = templateService.renderTemplate(MUTE_NOTIFICATION_TEMPLATE, muteNotification); String muteNotificationMessage = templateService.renderTemplate(MUTE_NOTIFICATION_TEMPLATE, muteNotification);
CompletableFuture<Message> messageCompletableFuture = messageService.sendMessageToUser(memberBeingMuted.getUser(), muteNotificationMessage); CompletableFuture<Message> messageCompletableFuture = messageService.sendMessageToUser(memberBeingMuted.getUser(), muteNotificationMessage);
messageCompletableFuture.exceptionally(throwable -> { messageCompletableFuture.exceptionally(throwable -> {
TextChannel feedBackChannel = botService.getTextChannelFromServer(message.getServerId(), message.getChannelId()); TextChannel feedBackChannel = botService.getTextChannelFromServer(message.getServerId(), message.getChannelId());
feedBackChannel.sendMessage(throwable.getMessage()).submit().whenComplete((exceptionMessage, innerThrowable) -> feedBackChannel.sendMessage(throwable.getMessage()).submit().whenComplete((exceptionMessage, innerThrowable) -> {
notificationFuture.complete(null) notificationFuture.complete(null);
); log.info("Successfully notified user {} in server {} about mute.", memberBeingMuted.getId(), memberBeingMuted.getGuild().getId());
});
return null; return null;
}); });
messageCompletableFuture.thenAccept(message1 -> messageCompletableFuture.thenAccept(message1 ->
@@ -226,7 +227,7 @@ public class MuteServiceBean implements MuteService {
@Override @Override
public CompletableFuture<Void> muteMemberWithLog(MuteContext context) { public CompletableFuture<Void> muteMemberWithLog(MuteContext context) {
log.trace("Muting member with sending a mute log"); log.trace("Muting member {} in server {} and sending a mute log.", context.getMutedUser().getId(), context.getMutedUser().getGuild().getId());
AServer server = serverManagementService.loadOrCreate(context.getContext().getServerId()); AServer server = serverManagementService.loadOrCreate(context.getContext().getServerId());
Long nextCounterValue = counterService.getNextCounterValue(server, MUTE_COUNTER_KEY); Long nextCounterValue = counterService.getNextCounterValue(server, MUTE_COUNTER_KEY);
context.setMuteId(nextCounterValue); context.setMuteId(nextCounterValue);
@@ -244,14 +245,14 @@ public class MuteServiceBean implements MuteService {
} }
public CompletableFuture<Void> sendMuteLog(MuteContext muteLogModel) { public CompletableFuture<Void> sendMuteLog(MuteContext muteLogModel) {
log.trace("Sending mute log to the mute posttarget"); log.trace("Sending mute log to the mute posttarget.");
MessageToSend message = templateService.renderEmbedTemplate(MUTE_LOG_TEMPLATE, muteLogModel); MessageToSend message = templateService.renderEmbedTemplate(MUTE_LOG_TEMPLATE, muteLogModel);
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getContext().getServerId()); List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getContext().getServerId());
return FutureUtils.toSingleFutureGeneric(completableFutures); return FutureUtils.toSingleFutureGeneric(completableFutures);
} }
private CompletableFuture<Void> sendUnMuteLog(UnMuteLog muteLogModel) { private CompletableFuture<Void> sendUnMuteLog(UnMuteLog muteLogModel) {
log.trace("Sending unMute log to the mute posttarget"); log.trace("Sending unMute log to the mute posttarget.");
MessageToSend message = templateService.renderEmbedTemplate(UN_MUTE_LOG_TEMPLATE, muteLogModel); MessageToSend message = templateService.renderEmbedTemplate(UN_MUTE_LOG_TEMPLATE, muteLogModel);
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getServer().getId()); List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getServer().getId());
return FutureUtils.toSingleFutureGeneric(completableFutures); return FutureUtils.toSingleFutureGeneric(completableFutures);
@@ -313,7 +314,7 @@ public class MuteServiceBean implements MuteService {
@Override @Override
@Transactional @Transactional
public CompletableFuture<Void> endMute(Long muteId, Long serverId) { public CompletableFuture<Void> endMute(Long muteId, Long serverId) {
log.info("UnMuting the mute {}", muteId); log.info("UnMuting the mute {} in server {}", muteId, serverId);
Optional<Mute> muteOptional = muteManagementService.findMute(muteId, serverId); Optional<Mute> muteOptional = muteManagementService.findMute(muteId, serverId);
if(muteOptional.isPresent()) { if(muteOptional.isPresent()) {
return endMute(muteOptional.get()); return endMute(muteOptional.get());
@@ -324,6 +325,7 @@ public class MuteServiceBean implements MuteService {
@Override @Override
public void completelyUnMuteUser(AUserInAServer aUserInAServer) { public void completelyUnMuteUser(AUserInAServer aUserInAServer) {
log.info("Completely unmuting user {} in server {}.", aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
List<Mute> allMutesOfUser = muteManagementService.getAllMutesOf(aUserInAServer); List<Mute> allMutesOfUser = muteManagementService.getAllMutesOf(aUserInAServer);
allMutesOfUser.forEach(mute -> { allMutesOfUser.forEach(mute -> {
mute.setMuteEnded(true); mute.setMuteEnded(true);

View File

@@ -25,6 +25,7 @@ import java.util.function.Consumer;
@Slf4j @Slf4j
public class PurgeServiceBean implements PurgeService { public class PurgeServiceBean implements PurgeService {
public static final int PURGE_MAX_MESSAGES = 100;
@Autowired @Autowired
private MessageService messageService; private MessageService messageService;
@@ -39,12 +40,12 @@ public class PurgeServiceBean implements PurgeService {
private CompletableFuture<Void> purgeMessages(Integer amountToDelete, TextChannel channel, Long startId, Member purgedMember, Integer totalCount, Integer currentCount, Long statusMessageId) { private CompletableFuture<Void> purgeMessages(Integer amountToDelete, TextChannel channel, Long startId, Member purgedMember, Integer totalCount, Integer currentCount, Long statusMessageId) {
int toDeleteInThisIteration; int toDeleteInThisIteration;
int messageLimit = 100; if(amountToDelete >= PURGE_MAX_MESSAGES){
if(amountToDelete >= messageLimit){ toDeleteInThisIteration = PURGE_MAX_MESSAGES;
toDeleteInThisIteration = messageLimit;
} else { } else {
toDeleteInThisIteration = amountToDelete % messageLimit; toDeleteInThisIteration = amountToDelete % PURGE_MAX_MESSAGES;
} }
log.info("Purging {} this iteration ({}/{}) messages in channel {} in server {}.", toDeleteInThisIteration, currentCount, totalCount, channel.getId(), channel.getGuild().getId());
CompletableFuture<MessageHistory> historyFuture = channel.getHistoryBefore(startId, toDeleteInThisIteration).submit(); CompletableFuture<MessageHistory> historyFuture = channel.getHistoryBefore(startId, toDeleteInThisIteration).submit();
CompletableFuture<Long> statusMessageFuture = getOrCreatedStatusMessage(channel, totalCount, statusMessageId); CompletableFuture<Long> statusMessageFuture = getOrCreatedStatusMessage(channel, totalCount, statusMessageId);
@@ -57,6 +58,7 @@ public class PurgeServiceBean implements PurgeService {
List<Message> messagesToDeleteNow = filterMessagesToDelete(retrievedHistory, purgedMember); List<Message> messagesToDeleteNow = filterMessagesToDelete(retrievedHistory, purgedMember);
Long currentStatusMessageId = statusMessageFuture.get(); Long currentStatusMessageId = statusMessageFuture.get();
if(messagesToDeleteNow.size() == 0) { if(messagesToDeleteNow.size() == 0) {
log.warn("No messages found to delete, all were filtered.");
deletionFuture.completeExceptionally(new NoMessageFoundException()); deletionFuture.completeExceptionally(new NoMessageFoundException());
channel.deleteMessageById(currentStatusMessageId).queueAfter(5, TimeUnit.SECONDS); channel.deleteMessageById(currentStatusMessageId).queueAfter(5, TimeUnit.SECONDS);
return; return;
@@ -64,7 +66,7 @@ public class PurgeServiceBean implements PurgeService {
Message latestMessage = messagesToDeleteNow.get(messagesToDeleteNow.size() - 1); Message latestMessage = messagesToDeleteNow.get(messagesToDeleteNow.size() - 1);
log.trace("Deleting {} messages directly", messagesToDeleteNow.size()); log.trace("Deleting {} messages directly", messagesToDeleteNow.size());
int newCurrentCount = currentCount + messagesToDeleteNow.size(); int newCurrentCount = currentCount + messagesToDeleteNow.size();
int newAmountToDelete = amountToDelete - messageLimit; int newAmountToDelete = amountToDelete - PURGE_MAX_MESSAGES;
Consumer<Void> consumer = deletionConsumer(newAmountToDelete, channel, purgedMember, totalCount, newCurrentCount, deletionFuture, currentStatusMessageId, latestMessage); Consumer<Void> consumer = deletionConsumer(newAmountToDelete, channel, purgedMember, totalCount, newCurrentCount, deletionFuture, currentStatusMessageId, latestMessage);
if (messagesToDeleteNow.size() > 1) { if (messagesToDeleteNow.size() > 1) {
bulkDeleteMessages(channel, deletionFuture, messagesToDeleteNow, consumer); bulkDeleteMessages(channel, deletionFuture, messagesToDeleteNow, consumer);
@@ -97,10 +99,12 @@ public class PurgeServiceBean implements PurgeService {
private CompletableFuture<Long> getOrCreatedStatusMessage(TextChannel channel, Integer totalCount, Long statusMessageId) { private CompletableFuture<Long> getOrCreatedStatusMessage(TextChannel channel, Integer totalCount, Long statusMessageId) {
CompletableFuture<Long> statusMessageFuture; CompletableFuture<Long> statusMessageFuture;
if(statusMessageId == 0) { if(statusMessageId == 0) {
log.trace("Creating new status message in channel {} in server {} because of puring.", channel.getIdLong(), channel.getGuild().getId());
PurgeStatusUpdateModel model = PurgeStatusUpdateModel.builder().currentlyDeleted(0).totalToDelete(totalCount).build(); PurgeStatusUpdateModel model = PurgeStatusUpdateModel.builder().currentlyDeleted(0).totalToDelete(totalCount).build();
MessageToSend messageToSend = templateService.renderTemplateToMessageToSend("purge_status_update", model); MessageToSend messageToSend = templateService.renderTemplateToMessageToSend("purge_status_update", model);
statusMessageFuture = messageService.createStatusMessageId(messageToSend, channel); statusMessageFuture = messageService.createStatusMessageId(messageToSend, channel);
} else { } else {
log.trace("Using existing status message {}.", statusMessageId);
statusMessageFuture = CompletableFuture.completedFuture(statusMessageId); statusMessageFuture = CompletableFuture.completedFuture(statusMessageId);
} }
return statusMessageFuture; return statusMessageFuture;
@@ -108,16 +112,20 @@ public class PurgeServiceBean implements PurgeService {
private List<Message> filterMessagesToDelete(List<Message> retrievedHistory, Member purgedMember) { private List<Message> filterMessagesToDelete(List<Message> retrievedHistory, Member purgedMember) {
long twoWeeksAgo = TimeUtil.getDiscordTimestamp((System.currentTimeMillis() - (14 * 24 * 60 * 60 * 1000))); long twoWeeksAgo = TimeUtil.getDiscordTimestamp((System.currentTimeMillis() - (14 * 24 * 60 * 60 * 1000)));
log.trace("Filtering messages older than {}.", twoWeeksAgo);
List<Message> messagesToDeleteNow = new ArrayList<>(); List<Message> messagesToDeleteNow = new ArrayList<>();
for (Message messageObj : retrievedHistory) { for (Message messageObj : retrievedHistory) {
if (MiscUtil.parseSnowflake(messageObj.getId()) > twoWeeksAgo) { if (MiscUtil.parseSnowflake(messageObj.getId()) > twoWeeksAgo) {
if(purgedMember != null) { if(purgedMember != null) {
if(messageObj.getAuthor().getIdLong() == purgedMember.getIdLong()) { if(messageObj.getAuthor().getIdLong() == purgedMember.getIdLong()) {
log.trace("Message {} is from filtered user {}. Purging.", messageObj.getId(), purgedMember.getIdLong());
messagesToDeleteNow.add(messageObj); messagesToDeleteNow.add(messageObj);
} }
} else { } else {
messagesToDeleteNow.add(messageObj); messagesToDeleteNow.add(messageObj);
} }
} else {
log.trace("Message {} was older than {}. Not purging.", messageObj.getId(), twoWeeksAgo);
} }
} }
return messagesToDeleteNow; return messagesToDeleteNow;
@@ -125,7 +133,8 @@ public class PurgeServiceBean implements PurgeService {
private Consumer<Void> deletionConsumer(Integer amountToDelete, TextChannel channel, Member purgedMember, Integer totalCount, Integer currentCount, CompletableFuture<Void> deletionFuture, Long currentStatusMessageId, Message earliestMessage) { private Consumer<Void> deletionConsumer(Integer amountToDelete, TextChannel channel, Member purgedMember, Integer totalCount, Integer currentCount, CompletableFuture<Void> deletionFuture, Long currentStatusMessageId, Message earliestMessage) {
return aVoid -> { return aVoid -> {
if (amountToDelete > 1) { if (amountToDelete >= 1) {
log.trace("Still more than 1 message to delete. Continuing.");
purgeMessages(amountToDelete, channel, earliestMessage.getIdLong(), purgedMember, totalCount, currentCount, currentStatusMessageId).whenComplete((avoid, throwable) -> { purgeMessages(amountToDelete, channel, earliestMessage.getIdLong(), purgedMember, totalCount, currentCount, currentStatusMessageId).whenComplete((avoid, throwable) -> {
if (throwable != null) { if (throwable != null) {
deletionFuture.completeExceptionally(throwable); deletionFuture.completeExceptionally(throwable);
@@ -135,10 +144,11 @@ public class PurgeServiceBean implements PurgeService {
} }
); );
} else { } else {
log.trace("Completed purging of {} messages.", totalCount);
channel.deleteMessageById(currentStatusMessageId).queueAfter(5, TimeUnit.SECONDS); channel.deleteMessageById(currentStatusMessageId).queueAfter(5, TimeUnit.SECONDS);
deletionFuture.complete(null); deletionFuture.complete(null);
} }
log.info("Setting status for {} out of {}", currentCount, totalCount); log.trace("Setting status for {} out of {}", currentCount, totalCount);
PurgeStatusUpdateModel finalUpdateModel = PurgeStatusUpdateModel.builder().currentlyDeleted(currentCount).totalToDelete(totalCount).build(); PurgeStatusUpdateModel finalUpdateModel = PurgeStatusUpdateModel.builder().currentlyDeleted(currentCount).totalToDelete(totalCount).build();
MessageToSend finalUpdateMessage = templateService.renderTemplateToMessageToSend("purge_status_update", finalUpdateModel); MessageToSend finalUpdateMessage = templateService.renderTemplateToMessageToSend("purge_status_update", finalUpdateModel);
messageService.updateStatusMessage(channel, currentStatusMessageId, finalUpdateMessage); messageService.updateStatusMessage(channel, currentStatusMessageId, finalUpdateMessage);

View File

@@ -98,6 +98,8 @@ public class WarnServiceBean implements WarnService {
@Transactional @Transactional
public void persistWarning(WarnContext context) { public void persistWarning(WarnContext context) {
log.info("Persisting warning {} in server {} for user {} by user {}.",
context.getWarnId(), context.getGuild().getId(), context.getWarnedMember().getId(), context.getMember().getId());
AUserInAServer warnedUser = userInServerManagementService.loadUser(context.getWarnedMember()); AUserInAServer warnedUser = userInServerManagementService.loadUser(context.getWarnedMember());
AUserInAServer warningUser = userInServerManagementService.loadUser(context.getMember()); AUserInAServer warningUser = userInServerManagementService.loadUser(context.getMember());
warnManagementService.createWarning(warnedUser, warningUser, context.getReason(), context.getWarnId()); warnManagementService.createWarning(warnedUser, warningUser, context.getReason(), context.getWarnId());
@@ -109,6 +111,7 @@ public class WarnServiceBean implements WarnService {
public CompletableFuture<Void> decayWarningsForServer(AServer server) { public CompletableFuture<Void> decayWarningsForServer(AServer server) {
Long days = configService.getLongValue(WarningDecayFeature.DECAY_DAYS_KEY, server.getId()); Long days = configService.getLongValue(WarningDecayFeature.DECAY_DAYS_KEY, server.getId());
Instant cutOffDay = Instant.now().minus(days, ChronoUnit.DAYS); Instant cutOffDay = Instant.now().minus(days, ChronoUnit.DAYS);
log.info("Decaying warnings on server {} which are older than {}.", server.getId(), cutOffDay);
List<Warning> warningsToDecay = warnManagementService.getActiveWarningsInServerOlderThan(server, cutOffDay); List<Warning> warningsToDecay = warnManagementService.getActiveWarningsInServerOlderThan(server, cutOffDay);
List<Long> warningIds = flattenWarnings(warningsToDecay); List<Long> warningIds = flattenWarnings(warningsToDecay);
Long serverId = server.getId(); Long serverId = server.getId();
@@ -129,6 +132,7 @@ public class WarnServiceBean implements WarnService {
@Transactional @Transactional
public void decayWarnings(List<Long> warningIds, Long serverId) { public void decayWarnings(List<Long> warningIds, Long serverId) {
Instant now = Instant.now(); Instant now = Instant.now();
log.info("Decaying {} warnings.", warningIds.size());
warningIds.forEach(warningId -> { warningIds.forEach(warningId -> {
Optional<Warning> warningOptional = warnManagementService.findById(warningId, serverId); Optional<Warning> warningOptional = warnManagementService.findById(warningId, serverId);
warningOptional.ifPresent(warning -> warningOptional.ifPresent(warning ->
@@ -142,11 +146,13 @@ public class WarnServiceBean implements WarnService {
@Override @Override
public void decayWarning(Warning warning, Instant now) { public void decayWarning(Warning warning, Instant now) {
log.trace("Decaying warning {} in server {} with date {}.", warning.getWarnId().getId(), warning.getWarnId().getServerId(), now);
warning.setDecayDate(now); warning.setDecayDate(now);
warning.setDecayed(true); warning.setDecayed(true);
} }
private CompletableFuture<Void> logDecayedWarnings(AServer server, List<Warning> warningsToDecay) { private CompletableFuture<Void> logDecayedWarnings(AServer server, List<Warning> warningsToDecay) {
log.trace("Logging decaying {} warnings in server {}.", warningsToDecay.size(), server.getId());
List<WarnDecayWarning> warnDecayWarnings = new ArrayList<>(); List<WarnDecayWarning> warnDecayWarnings = new ArrayList<>();
warningsToDecay.forEach(warning -> { warningsToDecay.forEach(warning -> {
WarnDecayWarning warnDecayWarning = WarnDecayWarning WarnDecayWarning warnDecayWarning = WarnDecayWarning
@@ -172,6 +178,7 @@ public class WarnServiceBean implements WarnService {
public CompletableFuture<Void> decayAllWarningsForServer(AServer server, boolean logWarnings) { public CompletableFuture<Void> decayAllWarningsForServer(AServer server, boolean logWarnings) {
List<Warning> warningsToDecay = warnManagementService.getActiveWarningsInServerOlderThan(server, Instant.now()); List<Warning> warningsToDecay = warnManagementService.getActiveWarningsInServerOlderThan(server, Instant.now());
List<Long> warnIds = flattenWarnings(warningsToDecay); List<Long> warnIds = flattenWarnings(warningsToDecay);
log.info("Decaying ALL warning in server {} with logging {}.", server.getId(), logWarnings);
Long serverId = server.getId(); Long serverId = server.getId();
if(logWarnings) { if(logWarnings) {
return logDecayedWarnings(server, warningsToDecay).thenAccept(aVoid -> return logDecayedWarnings(server, warningsToDecay).thenAccept(aVoid ->

View File

@@ -43,6 +43,7 @@ public class MuteRoleManagementServiceBean implements MuteRoleManagementService
public MuteRole setMuteRoleForServer(AServer server, ARole role) { public MuteRole setMuteRoleForServer(AServer server, ARole role) {
log.info("Setting muted role for server {} to role {}", server.getId(), role.getId()); log.info("Setting muted role for server {} to role {}", server.getId(), role.getId());
if(!muteRoleForServerExists(server)) { if(!muteRoleForServerExists(server)) {
log.trace("Mute role did not exist yet, updating for server {}.", server.getId());
return createMuteRoleForServer(server, role); return createMuteRoleForServer(server, role);
} else { } else {
MuteRole existing = retrieveMuteRoleForServer(server); MuteRole existing = retrieveMuteRoleForServer(server);

View File

@@ -6,12 +6,14 @@ import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.CounterService; import dev.sheldan.abstracto.core.service.CounterService;
import dev.sheldan.abstracto.moderation.models.database.UserNote; import dev.sheldan.abstracto.moderation.models.database.UserNote;
import dev.sheldan.abstracto.moderation.repository.UserNoteRepository; import dev.sheldan.abstracto.moderation.repository.UserNoteRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@Component @Component
@Slf4j
public class UserNoteManagementServiceBean implements UserNoteManagementService { public class UserNoteManagementServiceBean implements UserNoteManagementService {
@Autowired @Autowired
@@ -25,6 +27,7 @@ public class UserNoteManagementServiceBean implements UserNoteManagementService
@Override @Override
public UserNote createUserNote(AUserInAServer aUserInAServer, String note) { public UserNote createUserNote(AUserInAServer aUserInAServer, String note) {
Long id = counterService.getNextCounterValue(aUserInAServer.getServerReference(), USER_NOTE_COUNTER_KEY); Long id = counterService.getNextCounterValue(aUserInAServer.getServerReference(), USER_NOTE_COUNTER_KEY);
log.info("Creating user note with id {} for user {} in server {}.", id, aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
ServerSpecificId userNoteId = new ServerSpecificId(aUserInAServer.getServerReference().getId(), id); ServerSpecificId userNoteId = new ServerSpecificId(aUserInAServer.getServerReference().getId(), id);
UserNote newNote = UserNote UserNote newNote = UserNote
.builder() .builder()
@@ -38,13 +41,14 @@ public class UserNoteManagementServiceBean implements UserNoteManagementService
} }
@Override @Override
public void deleteNote(Long id) { public void deleteNote(Long id, AServer server) {
userNoteRepository.deleteById(id); log.info("Deleting user note with id {} in server {}.", id, server.getId());
userNoteRepository.deleteByUserNoteId_IdAndUserNoteId_ServerId(id, server.getId());
} }
@Override @Override
public boolean noteExists(Long id) { public boolean noteExists(Long id, AServer server) {
return userNoteRepository.existsById(id); return userNoteRepository.existsByUserNoteId_IdAndUserNoteId_ServerId(id, server.getId());
} }
@Override @Override

View File

@@ -5,6 +5,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.moderation.models.database.Warning; import dev.sheldan.abstracto.moderation.models.database.Warning;
import dev.sheldan.abstracto.moderation.repository.WarnRepository; import dev.sheldan.abstracto.moderation.repository.WarnRepository;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -13,6 +14,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component @Component
@Slf4j
public class WarnManagementServiceBean implements WarnManagementService { public class WarnManagementServiceBean implements WarnManagementService {
@Autowired @Autowired
@@ -20,6 +22,8 @@ public class WarnManagementServiceBean implements WarnManagementService {
@Override @Override
public Warning createWarning(AUserInAServer warnedAUser, AUserInAServer warningAUser, String reason, Long warnId) { public Warning createWarning(AUserInAServer warnedAUser, AUserInAServer warningAUser, String reason, Long warnId) {
log.info("Creating warning with id {} for user {} in server {} cast by user {}.",
warnId, warnedAUser.getUserReference().getId(), warningAUser.getServerReference().getId(), warningAUser.getUserReference().getId());
ServerSpecificId warningId = new ServerSpecificId(warnId, warningAUser.getServerReference().getId()); ServerSpecificId warningId = new ServerSpecificId(warnId, warningAUser.getServerReference().getId());
Warning warning = Warning.builder() Warning warning = Warning.builder()
.reason(reason) .reason(reason)
@@ -66,6 +70,7 @@ public class WarnManagementServiceBean implements WarnManagementService {
@Override @Override
public void deleteWarning(Warning warning) { public void deleteWarning(Warning warning) {
log.info("Deleting warning with id {} in server {}.", warning.getWarnId().getId(), warning.getWarnId().getServerId());
warnRepository.delete(warning); warnRepository.delete(warning);
} }

View File

@@ -37,16 +37,16 @@ public class DeleteNoteTest {
@Test @Test
public void testDeleteExistingNote() { public void testDeleteExistingNote() {
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(NOTE_ID)); CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(NOTE_ID));
when(userNoteManagementService.noteExists(NOTE_ID)).thenReturn(true); when(userNoteManagementService.noteExists(NOTE_ID, parameters.getUserInitiatedContext().getServer())).thenReturn(true);
CommandResult result = testUnit.execute(parameters); CommandResult result = testUnit.execute(parameters);
CommandTestUtilities.checkSuccessfulCompletion(result); CommandTestUtilities.checkSuccessfulCompletion(result);
verify(userNoteManagementService, times(1)).deleteNote(NOTE_ID); verify(userNoteManagementService, times(1)).deleteNote(NOTE_ID, parameters.getUserInitiatedContext().getServer());
} }
@Test @Test
public void testDeleteNotExistingNote() { public void testDeleteNotExistingNote() {
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(NOTE_ID)); CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(NOTE_ID));
when(userNoteManagementService.noteExists(NOTE_ID)).thenReturn(false); when(userNoteManagementService.noteExists(NOTE_ID, parameters.getUserInitiatedContext().getServer())).thenReturn(false);
when(templateService.renderSimpleTemplate(DeleteNote.NOTE_NOT_FOUND_EXCEPTION_TEMPLATE)).thenReturn("error"); when(templateService.renderSimpleTemplate(DeleteNote.NOTE_NOT_FOUND_EXCEPTION_TEMPLATE)).thenReturn("error");
CommandResult result = testUnit.execute(parameters); CommandResult result = testUnit.execute(parameters);
Assert.assertEquals(ResultState.ERROR, result.getResult()); Assert.assertEquals(ResultState.ERROR, result.getResult());

View File

@@ -10,6 +10,7 @@ import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction; import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import net.dv8tion.jda.api.utils.TimeUtil; import net.dv8tion.jda.api.utils.TimeUtil;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
@@ -77,6 +78,15 @@ public class PurgeServiceBeanTest {
@Mock @Mock
private AuditableRestAction deleteStatusAction; private AuditableRestAction deleteStatusAction;
@Mock
private Guild guild;
@Before
public void setup() {
when(textChannel.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("1");
}
@Test @Test
public void testPurgeMessageViaStartMessage() { public void testPurgeMessageViaStartMessage() {
Integer amountToDelete = 50; Integer amountToDelete = 50;

View File

@@ -118,6 +118,7 @@ public class WarnServiceBeanTest {
@Test @Test
public void testDecayWarning() { public void testDecayWarning() {
Instant date = Instant.now(); Instant date = Instant.now();
when(firstWarning.getWarnId()).thenReturn(new ServerSpecificId(3L, 4L));
testUnit.decayWarning(firstWarning, date); testUnit.decayWarning(firstWarning, date);
verify(firstWarning, times(1)).setDecayed(true); verify(firstWarning, times(1)).setDecayed(true);
verify(firstWarning, times(1)).setDecayDate(date); verify(firstWarning, times(1)).setDecayDate(date);

View File

@@ -53,14 +53,14 @@ public class UserNoteManagementServiceBeanTest {
@Test @Test
public void testDeleteNote() { public void testDeleteNote() {
testUnit.deleteNote(NOTE_ID); testUnit.deleteNote(NOTE_ID, server);
verify(userNoteRepository, times(1)).deleteById(NOTE_ID); verify(userNoteRepository, times(1)).deleteByUserNoteId_IdAndUserNoteId_ServerId(NOTE_ID, server.getId());
} }
@Test @Test
public void testNoteExists() { public void testNoteExists() {
when(userNoteRepository.existsById(NOTE_ID)).thenReturn(true); when(userNoteRepository.existsByUserNoteId_IdAndUserNoteId_ServerId(NOTE_ID, server.getId())).thenReturn(true);
Assert.assertTrue(testUnit.noteExists(NOTE_ID)); Assert.assertTrue(testUnit.noteExists(NOTE_ID, server));
} }
@Test @Test

View File

@@ -1,5 +1,6 @@
package dev.sheldan.abstracto.moderation.service.management; package dev.sheldan.abstracto.moderation.service.management;
import dev.sheldan.abstracto.core.models.ServerSpecificId;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.moderation.models.database.Warning; import dev.sheldan.abstracto.moderation.models.database.Warning;
@@ -130,6 +131,6 @@ public class WarnManagementServiceBeanTest {
} }
private Warning getWarning() { private Warning getWarning() {
return Warning.builder().build(); return Warning.builder().warnId(new ServerSpecificId(3L, 4L)).build();
} }
} }

View File

@@ -8,8 +8,8 @@ import java.util.List;
public interface UserNoteManagementService { public interface UserNoteManagementService {
UserNote createUserNote(AUserInAServer aUserInAServer, String note); UserNote createUserNote(AUserInAServer aUserInAServer, String note);
void deleteNote(Long id); void deleteNote(Long id, AServer server);
boolean noteExists(Long id); boolean noteExists(Long id, AServer server);
List<UserNote> loadNotesForUser(AUserInAServer aUserInAServer); List<UserNote> loadNotesForUser(AUserInAServer aUserInAServer);
List<UserNote> loadNotesForServer(AServer server); List<UserNote> loadNotesForServer(AServer server);
} }

View File

@@ -18,6 +18,7 @@ import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
import dev.sheldan.abstracto.modmail.models.template.ModMailThreadExistsModel; import dev.sheldan.abstracto.modmail.models.template.ModMailThreadExistsModel;
import dev.sheldan.abstracto.modmail.service.ModMailThreadService; import dev.sheldan.abstracto.modmail.service.ModMailThreadService;
import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService; import dev.sheldan.abstracto.modmail.service.management.ModMailThreadManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -32,6 +33,7 @@ import java.util.concurrent.CompletableFuture;
* the {@link net.dv8tion.jda.api.entities.MessageChannel} * the {@link net.dv8tion.jda.api.entities.MessageChannel}
*/ */
@Component @Component
@Slf4j
public class Contact extends AbstractConditionableCommand { public class Contact extends AbstractConditionableCommand {
@Autowired @Autowired
@@ -53,6 +55,7 @@ public class Contact extends AbstractConditionableCommand {
// if this AUserInAServer already has an open thread, we should instead post a message // if this AUserInAServer already has an open thread, we should instead post a message
// containing a link to the channel, instead of opening a new one // containing a link to the channel, instead of opening a new one
if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) { if(modMailThreadManagementService.hasOpenModMailThreadForUser(user)) {
log.info("Modmail thread for user {} in server {} already exists. Notifying user {}.", commandContext.getAuthor().getId(), commandContext.getGuild().getId(), user.getUserReference().getId());
ModMailThreadExistsModel model = (ModMailThreadExistsModel) ContextConverter.fromCommandContext(commandContext, ModMailThreadExistsModel.class); ModMailThreadExistsModel model = (ModMailThreadExistsModel) ContextConverter.fromCommandContext(commandContext, ModMailThreadExistsModel.class);
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user); ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
model.setExistingModMailThread(existingThread); model.setExistingModMailThread(existingThread);

View File

@@ -5,6 +5,7 @@ import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.service.management.ConfigManagementService; import dev.sheldan.abstracto.core.service.management.ConfigManagementService;
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean; import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
import dev.sheldan.abstracto.templating.service.TemplateService; import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -16,6 +17,7 @@ import static dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean.MOD
* makes things easier * makes things easier
*/ */
@Component @Component
@Slf4j
public class ModMailConfigListener implements ServerConfigListener { public class ModMailConfigListener implements ServerConfigListener {
@@ -27,6 +29,7 @@ public class ModMailConfigListener implements ServerConfigListener {
@Override @Override
public void updateServerConfig(AServer server) { public void updateServerConfig(AServer server) {
log.info("Updating modmail related configuration for server {}.", server.getId());
configService.createIfNotExists(server.getId(), ModMailThreadServiceBean.MODMAIL_CATEGORY, 0L); configService.createIfNotExists(server.getId(), ModMailThreadServiceBean.MODMAIL_CATEGORY, 0L);
configService.createIfNotExists(server.getId(), MODMAIL_CLOSING_MESSAGE_TEXT, templateService.renderSimpleTemplate("modmail_closing_user_message_description")); configService.createIfNotExists(server.getId(), MODMAIL_CLOSING_MESSAGE_TEXT, templateService.renderSimpleTemplate("modmail_closing_user_message_description"));
} }

View File

@@ -43,11 +43,13 @@ public class ModMailMessageListener implements PrivateMessageReceivedListener {
public void execute(Message message) { public void execute(Message message) {
AUser user = userManagementService.loadUser(message.getAuthor().getIdLong()); AUser user = userManagementService.loadUser(message.getAuthor().getIdLong());
if(modMailThreadManagementService.hasOpenModMailThread(user)) { if(modMailThreadManagementService.hasOpenModMailThread(user)) {
log.trace("User {} has an open modmail thread. Forwarding message {}.", user.getId(), message.getId());
// there is only one open mod mail thread for a user at a time, so we can select the first one // there is only one open mod mail thread for a user at a time, so we can select the first one
// we cannot use the AUserInAServer directly, because a message in a private channel does not have a Member // we cannot use the AUserInAServer directly, because a message in a private channel does not have a Member
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadsForUser(user).get(0); ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadsForUser(user).get(0);
modMailThreadService.relayMessageToModMailThread(existingThread, message, new ArrayList<>()); modMailThreadService.relayMessageToModMailThread(existingThread, message, new ArrayList<>());
} else { } else {
log.info("User {} does not have an open modmail thread. Crating prompt.", user.getId());
modMailThreadService.createModMailPrompt(user, message); modMailThreadService.createModMailPrompt(user, message);
} }
} }

View File

@@ -30,6 +30,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
} }
// all message must be from the same thread // all message must be from the same thread
ModMailThread thread = modMailMessages.get(0).getThreadReference(); ModMailThread thread = modMailMessages.get(0).getThreadReference();
log.trace("Loading {} mod mail messages from thread {} in server {}.", modMailMessages.size(), thread.getId(), thread.getServer().getId());
List<ServerChannelMessage> messageIds = new ArrayList<>(); List<ServerChannelMessage> messageIds = new ArrayList<>();
modMailMessages.forEach(modMailMessage -> { modMailMessages.forEach(modMailMessage -> {
ServerChannelMessage.ServerChannelMessageBuilder serverChannelMessageBuilder = ServerChannelMessage ServerChannelMessage.ServerChannelMessageBuilder serverChannelMessageBuilder = ServerChannelMessage
@@ -37,6 +38,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
.messageId(modMailMessage.getMessageId()); .messageId(modMailMessage.getMessageId());
// if its not from a private chat, we need to set the server and channel ID in order to fetch the data // if its not from a private chat, we need to set the server and channel ID in order to fetch the data
if(Boolean.FALSE.equals(modMailMessage.getDmChannel())) { if(Boolean.FALSE.equals(modMailMessage.getDmChannel())) {
log.trace("Message {} was from DM.", modMailMessage.getMessageId());
serverChannelMessageBuilder serverChannelMessageBuilder
.channelId(modMailMessage.getThreadReference().getChannel().getId()) .channelId(modMailMessage.getThreadReference().getChannel().getId())
.serverId(modMailMessage.getThreadReference().getServer().getId()); .serverId(modMailMessage.getThreadReference().getServer().getId());
@@ -55,6 +57,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
botService.getInstance().openPrivateChannelById(thread.getUser().getUserReference().getId()).queue(privateChannel -> { botService.getInstance().openPrivateChannelById(thread.getUser().getUserReference().getId()).queue(privateChannel -> {
Iterator<CompletableFuture<Message>> iterator = messageFutures.iterator(); Iterator<CompletableFuture<Message>> iterator = messageFutures.iterator();
messageIds.forEach(serverChannelMessage -> { messageIds.forEach(serverChannelMessage -> {
log.trace("Loading message {}.", serverChannelMessage.getMessageId());
// TODO fix out of order promises // TODO fix out of order promises
// depending what the source of the message is, we need to fetch the message from the correct channel // depending what the source of the message is, we need to fetch the message from the correct channel
if(serverChannelMessage.getChannelId() == null){ if(serverChannelMessage.getChannelId() == null){

View File

@@ -5,10 +5,12 @@ import dev.sheldan.abstracto.core.command.service.management.FeatureManagementSe
import dev.sheldan.abstracto.core.models.database.ARole; import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.modmail.config.ModMailFeatures; import dev.sheldan.abstracto.modmail.config.ModMailFeatures;
import dev.sheldan.abstracto.modmail.service.management.ModMailRoleManagementService; import dev.sheldan.abstracto.modmail.service.management.ModMailRoleManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@Slf4j
public class ModMailRoleServiceBean implements ModMailRoleService { public class ModMailRoleServiceBean implements ModMailRoleService {
@Autowired @Autowired
@@ -22,15 +24,17 @@ public class ModMailRoleServiceBean implements ModMailRoleService {
@Override @Override
public void addRoleToModMailRoles(ARole role) { public void addRoleToModMailRoles(ARole role) {
if(!modMailRoleManagementService.isRoleAlreadyAssigned(role, role.getServer())) { log.info("Adding role {} to modmail roles in server {}.", role.getId(), role.getServer().getId());
modMailRoleManagementService.addRoleToModMailRoles(role, role.getServer()); if(!modMailRoleManagementService.isRoleAlreadyAssigned(role)) {
modMailRoleManagementService.addRoleToModMailRoles(role);
} }
commandService.allowFeatureForRole(ModMailFeatures.MOD_MAIL, role); commandService.allowFeatureForRole(ModMailFeatures.MOD_MAIL, role);
} }
@Override @Override
public void removeRoleFromModMailRoles(ARole role) { public void removeRoleFromModMailRoles(ARole role) {
modMailRoleManagementService.removeRoleFromModMailRoles(role, role.getServer()); log.info("Remove role {} from modmail roles in server {}.", role.getId(), role.getServer().getId());
modMailRoleManagementService.removeRoleFromModMailRoles(role);
commandService.disAllowFeatureForRole(ModMailFeatures.MOD_MAIL, role); commandService.disAllowFeatureForRole(ModMailFeatures.MOD_MAIL, role);
} }
} }

View File

@@ -38,7 +38,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.Instant; import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@Component @Component
@Slf4j @Slf4j
@@ -134,6 +133,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
Long serverId = aUserInAServer.getAUserInAServer().getServerReference().getId(); Long serverId = aUserInAServer.getAUserInAServer().getServerReference().getId();
Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId); Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId);
User user = aUserInAServer.getMember().getUser(); User user = aUserInAServer.getMember().getUser();
log.info("Creating modmail channel for user {} in category {} on server {}.", user.getId(), categoryId, serverId);
CompletableFuture<TextChannel> textChannelFuture = channelService.createTextChannel(user.getName() + user.getDiscriminator(), aUserInAServer.getAUserInAServer().getServerReference(), categoryId); CompletableFuture<TextChannel> textChannelFuture = channelService.createTextChannel(user.getName() + user.getDiscriminator(), aUserInAServer.getAUserInAServer().getServerReference(), categoryId);
return textChannelFuture.thenCompose(channel -> { return textChannelFuture.thenCompose(channel -> {
@@ -153,12 +153,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
*/ */
@Transactional @Transactional
public CompletableFuture<Void> performModMailThreadSetup(FullUserInServer aUserInAServer, Message initialMessage, TextChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions) { public CompletableFuture<Void> performModMailThreadSetup(FullUserInServer aUserInAServer, Message initialMessage, TextChannel channel, boolean userInitiated, List<UndoActionInstance> undoActions) {
log.info("Performing modmail thread setup for channel {} for user {} in server {}. It was initiated by a user: {}.", channel.getIdLong(), aUserInAServer.getMember().getId(), channel.getGuild().getId(), userInitiated);
Long userInServerId = aUserInAServer.getAUserInAServer().getUserInServerId(); Long userInServerId = aUserInAServer.getAUserInAServer().getUserInServerId();
CompletableFuture<Void> headerFuture = sendModMailHeader(channel, aUserInAServer); CompletableFuture<Void> headerFuture = sendModMailHeader(channel, aUserInAServer);
CompletableFuture<Void> userReplyMessage; CompletableFuture<Void> userReplyMessage;
if(initialMessage != null){ if(initialMessage != null){
log.trace("Sending initial message {} of user {} to modmail thread {}.", initialMessage.getId(), aUserInAServer.getMember().getId(), channel.getId());
userReplyMessage = self.sendUserReply(channel, null, initialMessage, aUserInAServer.getAUserInAServer()); userReplyMessage = self.sendUserReply(channel, null, initialMessage, aUserInAServer.getAUserInAServer());
} else { } else {
log.trace("No initial message to send.");
userReplyMessage = CompletableFuture.completedFuture(null); userReplyMessage = CompletableFuture.completedFuture(null);
} }
CompletableFuture notificationFuture; CompletableFuture notificationFuture;
@@ -175,9 +178,11 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Transactional @Transactional
public void setupModMailThreadInDB(Message initialMessage, TextChannel channel, Long userInServerId) { public void setupModMailThreadInDB(Message initialMessage, TextChannel channel, Long userInServerId) {
log.info("Persisting info about modmail thread {} in database.", channel.getIdLong());
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(userInServerId); AUserInAServer aUserInAServer = userInServerManagementService.loadUser(userInServerId);
ModMailThread thread = createThreadObject(channel, aUserInAServer); ModMailThread thread = createThreadObject(channel, aUserInAServer);
if(initialMessage != null) { if(initialMessage != null) {
log.trace("Adding initial message {} to modmail thread in channel {}.", initialMessage.getId(), channel.getId());
modMailMessageManagementService.addMessageToThread(thread, initialMessage, aUserInAServer, false, false); modMailMessageManagementService.addMessageToThread(thread, initialMessage, aUserInAServer, false, false);
} }
} }
@@ -188,7 +193,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
*/ */
@Transactional @Transactional
public CompletableFuture<Void> sendModMailNotification(FullUserInServer aUserInAServer) { public CompletableFuture<Void> sendModMailNotification(FullUserInServer aUserInAServer) {
log.info("Sending modmail notification for new modmail thread about user {} in server {}.", aUserInAServer.getMember().getId(), aUserInAServer.getMember().getGuild().getId());
List<ModMailRole> rolesToPing = modMailRoleManagementService.getRolesForServer(aUserInAServer.getAUserInAServer().getServerReference()); List<ModMailRole> rolesToPing = modMailRoleManagementService.getRolesForServer(aUserInAServer.getAUserInAServer().getServerReference());
log.trace("Pinging {} roles to notify about modmail thread about user {} in server {}.", rolesToPing.size(), aUserInAServer.getMember().getId(), aUserInAServer.getMember().getGuild().getId());
ModMailNotificationModel modMailNotificationModel = ModMailNotificationModel ModMailNotificationModel modMailNotificationModel = ModMailNotificationModel
.builder() .builder()
.threadUser(aUserInAServer) .threadUser(aUserInAServer)
@@ -206,6 +213,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @return The created instance of {@link ModMailThread} * @return The created instance of {@link ModMailThread}
*/ */
public ModMailThread createThreadObject(TextChannel channel, AUserInAServer user) { public ModMailThread createThreadObject(TextChannel channel, AUserInAServer user) {
log.info("Creating database objects related to modmail thread in channel {} and about user {} in server {}.", channel.getIdLong(), user.getUserReference().getId(), channel.getGuild().getId());
AChannel channel2 = channelManagementService.createChannel(channel.getIdLong(), AChannelType.TEXT, user.getServerReference()); AChannel channel2 = channelManagementService.createChannel(channel.getIdLong(), AChannelType.TEXT, user.getServerReference());
log.info("Creating mod mail thread in channel {} with db channel {}", channel.getIdLong(), channel2.getId()); log.info("Creating mod mail thread in channel {} with db channel {}", channel.getIdLong(), channel2.getId());
return modMailThreadManagementService.createModMailThread(user, channel2); return modMailThreadManagementService.createModMailThread(user, channel2);
@@ -213,6 +221,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override @Override
public void setModMailCategoryTo(Guild guild, Long categoryId) { public void setModMailCategoryTo(Guild guild, Long categoryId) {
log.info("Trying to set modmail category to {} in guild {}.", categoryId, guild.getId());
FeatureValidationResult result = FeatureValidationResult.builder().build(); FeatureValidationResult result = FeatureValidationResult.builder().build();
modMailFeatureValidator.validateModMailCategory(result, guild, categoryId); modMailFeatureValidator.validateModMailCategory(result, guild, categoryId);
if(result.getValidationResult()) { if(result.getValidationResult()) {
@@ -226,6 +235,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
List<AUserInAServer> knownServers = userInServerManagementService.getUserInAllServers(user.getId()); List<AUserInAServer> knownServers = userInServerManagementService.getUserInAllServers(user.getId());
// do nothing if we don't know the user // do nothing if we don't know the user
if(!knownServers.isEmpty()) { if(!knownServers.isEmpty()) {
log.info("There are {} shared servers between user and abstracto.", knownServers.size());
List<ServerChoice> availableGuilds = new ArrayList<>(); List<ServerChoice> availableGuilds = new ArrayList<>();
HashMap<String, AUserInAServer> choices = new HashMap<>(); HashMap<String, AUserInAServer> choices = new HashMap<>();
for (int i = 0; i < knownServers.size(); i++) { for (int i = 0; i < knownServers.size(); i++) {
@@ -246,6 +256,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
availableGuilds.add(serverChoice); availableGuilds.add(serverChoice);
} }
} }
log.info("There were {} shared servers found which have modmailenabled.", availableGuilds.size());
// if more than 1 server is available, show a choice dialog // if more than 1 server is available, show a choice dialog
if(availableGuilds.size() > 1) { if(availableGuilds.size() > 1) {
ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel
@@ -259,6 +270,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.setDescription(text) .setDescription(text)
.setAction(reactionEmote -> { .setAction(reactionEmote -> {
AUserInAServer chosenServer = choices.get(reactionEmote.getEmoji()); AUserInAServer chosenServer = choices.get(reactionEmote.getEmoji());
log.trace("Executing action for creationg a modmail thread in server {} for user {}.", chosenServer.getServerReference().getId(), chosenServer.getUserReference().getId());
Member memberInServer = botService.getMemberInServer(chosenServer); Member memberInServer = botService.getMemberInServer(chosenServer);
FullUserInServer fullUser = FullUserInServer.builder().member(memberInServer).aUserInAServer(chosenServer).build(); FullUserInServer fullUser = FullUserInServer.builder().member(memberInServer).aUserInAServer(chosenServer).build();
self.createModMailThreadForUser(fullUser, initialMessage, initialMessage.getChannel(), true, new ArrayList<>()).exceptionally(throwable -> { self.createModMailThreadForUser(fullUser, initialMessage, initialMessage.getChannel(), true, new ArrayList<>()).exceptionally(throwable -> {
@@ -267,10 +279,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
}); });
}) })
.build(); .build();
log.trace("Displaying server choice message for user {} in channel {}.", user.getId(), initialMessage.getChannel().getId());
menu.display(initialMessage.getChannel()); menu.display(initialMessage.getChannel());
} else if(availableGuilds.size() == 1) { } else if(availableGuilds.size() == 1) {
// if exactly one server is available, open the thread directly // if exactly one server is available, open the thread directly
AUserInAServer chosenServer = choices.get(availableGuilds.get(0).getReactionEmote()); AUserInAServer chosenServer = choices.get(availableGuilds.get(0).getReactionEmote());
log.info("Only one server available to modmail. Directly opening modmail thread for user {} in server {}.", chosenServer.getUserReference().getId(), chosenServer.getServerReference().getId());
Member memberInServer = botService.getMemberInServer(chosenServer); Member memberInServer = botService.getMemberInServer(chosenServer);
FullUserInServer fullUser = FullUserInServer.builder().member(memberInServer).aUserInAServer(chosenServer).build(); FullUserInServer fullUser = FullUserInServer.builder().member(memberInServer).aUserInAServer(chosenServer).build();
self.createModMailThreadForUser(fullUser, initialMessage, initialMessage.getChannel(), true, new ArrayList<>()).exceptionally(throwable -> { self.createModMailThreadForUser(fullUser, initialMessage, initialMessage.getChannel(), true, new ArrayList<>()).exceptionally(throwable -> {
@@ -278,6 +292,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
return null; return null;
}); });
} else { } else {
log.info("No server available to open a modmail thread in.");
// in case there is no server available, send an error message // in case there is no server available, send an error message
channelService.sendEmbedTemplateInChannel("modmail_no_server_available", new Object(), initialMessage.getChannel()); channelService.sendEmbedTemplateInChannel("modmail_no_server_available", new Object(), initialMessage.getChannel());
} }
@@ -294,6 +309,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @param aUserInAServer The {@link AUserInAServer} which the {@link ModMailThread} is about * @param aUserInAServer The {@link AUserInAServer} which the {@link ModMailThread} is about
*/ */
private CompletableFuture<Void> sendModMailHeader(TextChannel channel, FullUserInServer aUserInAServer) { private CompletableFuture<Void> sendModMailHeader(TextChannel channel, FullUserInServer aUserInAServer) {
log.trace("Sending modmail thread header for tread in channel {} on server {}.", channel.getIdLong(), channel.getGuild().getId());
ModMailThread latestThread = modMailThreadManagementService.getLatestModMailThread(aUserInAServer.getAUserInAServer()); ModMailThread latestThread = modMailThreadManagementService.getLatestModMailThread(aUserInAServer.getAUserInAServer());
List<ModMailThread> oldThreads = modMailThreadManagementService.getModMailThreadForUser(aUserInAServer.getAUserInAServer()); List<ModMailThread> oldThreads = modMailThreadManagementService.getModMailThreadForUser(aUserInAServer.getAUserInAServer());
ModMailThreaderHeader header = ModMailThreaderHeader ModMailThreaderHeader header = ModMailThreaderHeader
@@ -308,11 +324,13 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override @Override
public CompletableFuture<Void> relayMessageToModMailThread(ModMailThread modMailThread, Message message, List<UndoActionInstance> undoActions) { public CompletableFuture<Void> relayMessageToModMailThread(ModMailThread modMailThread, Message message, List<UndoActionInstance> undoActions) {
log.trace("Relaying message {} to modmail thread {} for user {} to server {}.", message.getId(), modMailThread.getId(), message.getAuthor().getIdLong(), modMailThread.getServer().getId());
Optional<TextChannel> textChannelFromServer = botService.getTextChannelFromServerOptional(modMailThread.getServer().getId(), modMailThread.getChannel().getId()); Optional<TextChannel> textChannelFromServer = botService.getTextChannelFromServerOptional(modMailThread.getServer().getId(), modMailThread.getChannel().getId());
if(textChannelFromServer.isPresent()) { if(textChannelFromServer.isPresent()) {
TextChannel textChannel = textChannelFromServer.get(); TextChannel textChannel = textChannelFromServer.get();
return self.sendUserReply(textChannel, modMailThread, message, modMailThread.getUser()); return self.sendUserReply(textChannel, modMailThread, message, modMailThread.getUser());
} else { } else {
log.warn("Closing modmail thread {}, because it seems the channel {} in server {} got deleted.", modMailThread.getId(), modMailThread.getChannel().getId(), modMailThread.getServer().getId());
// in this case there was no text channel on the server associated with the mod mail thread // in this case there was no text channel on the server associated with the mod mail thread
// close the existing one, so the user can start a new one // close the existing one, so the user can start a new one
self.closeModMailThreadInDb(modMailThread.getId()); self.closeModMailThreadInDb(modMailThread.getId());
@@ -348,6 +366,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.build(); .build();
subscribers.add(subscriber); subscribers.add(subscriber);
}); });
log.trace("Pinging {} subscribers for modmail thread {}.", subscriberList.size(), modMailThread.getId());
} }
ModMailUserReplyModel modMailUserReplyModel = ModMailUserReplyModel ModMailUserReplyModel modMailUserReplyModel = ModMailUserReplyModel
.builder() .builder()
@@ -359,7 +378,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_user_message", modMailUserReplyModel); MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_user_message", modMailUserReplyModel);
List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, textChannel); List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, textChannel);
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])) return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]))
.thenCompose(aVoid -> messageService.addReactionToMessageWithFuture("readReaction", textChannel.getGuild().getIdLong(), message)) .thenCompose(aVoid -> {
log.trace("Adding read reaction to initial message for mod mail thread in channel {}.", textChannel.getGuild().getId());
return messageService.addReactionToMessageWithFuture("readReaction", textChannel.getGuild().getIdLong(), message);
})
.thenAccept(aVoid -> { .thenAccept(aVoid -> {
if(modMailThreadExists) { if(modMailThreadExists) {
self.postProcessSendMessages(textChannel, completableFutures.get(0).join()); self.postProcessSendMessages(textChannel, completableFutures.get(0).join());
@@ -378,6 +400,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(textChannel.getIdLong()); Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(textChannel.getIdLong());
if(modMailThreadOpt.isPresent()) { if(modMailThreadOpt.isPresent()) {
ModMailThread modMailThread = modMailThreadOpt.get(); ModMailThread modMailThread = modMailThreadOpt.get();
log.trace("Adding message {} sent from user to modmail thread {} and setting status to {}.", message.getId(), modMailThread.getId(), ModMailThreadState.USER_REPLIED);
modMailMessageManagementService.addMessageToThread(modMailThread, message, modMailThread.getUser(), false, false); modMailMessageManagementService.addMessageToThread(modMailThread, message, modMailThread.getUser(), false, false);
// update the state of the thread // update the state of the thread
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.USER_REPLIED); modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.USER_REPLIED);
@@ -389,6 +412,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override @Override
public CompletableFuture<Void> relayMessageToDm(ModMailThread modMailThread, String text, Message message, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions) { public CompletableFuture<Void> relayMessageToDm(ModMailThread modMailThread, String text, Message message, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions) {
Long modMailThreadId = modMailThread.getId(); Long modMailThreadId = modMailThread.getId();
log.info("Relaying message {} to user {} in modmail thread {} on server {}.", message.getId(), modMailThread.getUser().getUserReference().getId(), modMailThread.getId(), modMailThread.getServer().getId());
User userById = botService.getInstance().getUserById(modMailThread.getUser().getUserReference().getId()); User userById = botService.getInstance().getUserById(modMailThread.getUser().getUserReference().getId());
if(userById != null) { if(userById != null) {
AUserInAServer moderator = userInServerManagementService.loadUser(message.getMember()); AUserInAServer moderator = userInServerManagementService.loadUser(message.getMember());
@@ -406,6 +430,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.anonymous(anonymous) .anonymous(anonymous)
.threadUser(fullThreadUser); .threadUser(fullThreadUser);
if(anonymous) { if(anonymous) {
log.trace("Message is sent anonymous.");
modMailModeratorReplyModelBuilder.moderator(botService.getBotInGuild(modMailThread.getServer())); modMailModeratorReplyModelBuilder.moderator(botService.getBotInGuild(modMailThread.getServer()));
} else { } else {
Member moderatorMember = botService.getMemberInServer(moderator); Member moderatorMember = botService.getMemberInServer(moderator);
@@ -441,6 +466,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
).toCompletableFuture().thenCompose(o -> o); ).toCompletableFuture().thenCompose(o -> o);
} else { } else {
log.trace("Not logging modmail thread {}.", modMailThreadId);
return self.afterSuccessfulLog(modMailThreadId, notifyUser, undoActions); return self.afterSuccessfulLog(modMailThreadId, notifyUser, undoActions);
} }
} }
@@ -456,6 +482,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
*/ */
@Transactional @Transactional
public CompletableFuture<Void> logMessagesToModMailLog(String note, Boolean notifyUser, Long modMailThreadId, List<UndoActionInstance> undoActions, List<CompletableFuture<Message>> messages) { public CompletableFuture<Void> logMessagesToModMailLog(String note, Boolean notifyUser, Long modMailThreadId, List<UndoActionInstance> undoActions, List<CompletableFuture<Message>> messages) {
log.trace("Logging {} modmail messages for modmail thread {}.", messages.size(), modMailThreadId);
try { try {
CompletableFutureList<Message> list = self.logModMailThread(modMailThreadId, messages, note, undoActions); CompletableFutureList<Message> list = self.logModMailThread(modMailThreadId, messages, note, undoActions);
return list.getMainFuture().thenCompose(avoid -> { return list.getMainFuture().thenCompose(avoid -> {
@@ -485,6 +512,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId); Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
if(modMailThreadOpt.isPresent()) { if(modMailThreadOpt.isPresent()) {
if(notifyUser) { if(notifyUser) {
log.trace("Notifying user about the closed modmail thread {}.", modMailThreadId);
ModMailThread modMailThread = modMailThreadOpt.get(); ModMailThread modMailThread = modMailThreadOpt.get();
User user = botService.getMemberInServer(modMailThread.getUser()).getUser(); User user = botService.getMemberInServer(modMailThread.getUser()).getUser();
HashMap<String, String> closingMessage = new HashMap<>(); HashMap<String, String> closingMessage = new HashMap<>();
@@ -494,6 +522,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
self.deleteChannelAndClose(modMailThreadId, undoActions) self.deleteChannelAndClose(modMailThreadId, undoActions)
); );
} else { } else {
log.trace("NOT Notifying user about the closed modmail thread {}.", modMailThreadId);
return deleteChannelAndClose(modMailThreadId, undoActions); return deleteChannelAndClose(modMailThreadId, undoActions);
} }
} else { } else {
@@ -515,6 +544,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
ModMailThread modMailThread = modMailThreadOpt.get(); ModMailThread modMailThread = modMailThreadOpt.get();
String failureMessage = "Failed to delete text channel containing mod mail thread {}"; String failureMessage = "Failed to delete text channel containing mod mail thread {}";
try { try {
log.trace("Deleting channel {} which contained the modmail thread {}.", modMailThread.getChannel().getId(), modMailThreadId);
return channelService.deleteTextChannel(modMailThread.getChannel()).thenAccept(avoid -> { return channelService.deleteTextChannel(modMailThread.getChannel()).thenAccept(avoid -> {
undoActions.clear(); undoActions.clear();
self.closeModMailThreadInDb(modMailThreadId); self.closeModMailThreadInDb(modMailThreadId);
@@ -546,7 +576,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
*/ */
@Transactional @Transactional
public CompletableFutureList<Message> logModMailThread(Long modMailThreadId, List<CompletableFuture<Message>> messages, String note, List<UndoActionInstance> undoActions) { public CompletableFutureList<Message> logModMailThread(Long modMailThreadId, List<CompletableFuture<Message>> messages, String note, List<UndoActionInstance> undoActions) {
log.info("Logging mod mail thread {}.", modMailThreadId); log.info("Logging mod mail thread {} with {} messages.", modMailThreadId, messages.size());
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId); Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
if(modMailThreadOpt.isPresent()) { if(modMailThreadOpt.isPresent()) {
ModMailThread modMailThread = modMailThreadOpt.get(); ModMailThread modMailThread = modMailThreadOpt.get();
@@ -554,8 +584,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
messages.forEach(future -> { messages.forEach(future -> {
try { try {
if(!future.isCompletedExceptionally()) { if(!future.isCompletedExceptionally()) {
Message loadedMessage = future.get(); Message loadedMessage = future.join();
if(loadedMessage != null) { if(loadedMessage != null) {
log.info("Logging message {} in modmail thread {}.", loadedMessage.getId(), modMailThreadId);
ModMailMessage modmailMessage = modMailThread.getMessages() ModMailMessage modmailMessage = modMailThread.getMessages()
.stream() .stream()
.filter(modMailMessage -> modMailMessage.getMessageId().equals(loadedMessage.getIdLong())) .filter(modMailMessage -> modMailMessage.getMessageId().equals(loadedMessage.getIdLong()))
@@ -569,10 +600,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.build(); .build();
loggedMessages.add(modMailLoggedMessageModel); loggedMessages.add(modMailLoggedMessageModel);
} }
} else {
log.warn("One future failed to load. Will not log a message in modmail thread {}.", modMailThreadId);
} }
} catch (InterruptedException | ExecutionException e) {
log.error("Error while executing future to retrieve reaction.", e);
Thread.currentThread().interrupt();
} catch (Exception e) { } catch (Exception e) {
log.error("Failed handle the loaded messages.", e); log.error("Failed handle the loaded messages.", e);
} }
@@ -585,10 +615,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.closedThread(modMailThread) .closedThread(modMailThread)
.note(note) .note(note)
.build(); .build();
log.trace("Sending close header and individual mod mail messages to mod mail log target."); log.trace("Sending close header and individual mod mail messages to mod mail log target for thread {}.", modMailThreadId);
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_header", headerModel); MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_header", headerModel);
List<CompletableFuture<Message>> closeHeaderFutures = postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_LOG, modMailThread.getServer().getId()); List<CompletableFuture<Message>> closeHeaderFutures = postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_LOG, modMailThread.getServer().getId());
// TODO in case the rendering fails, the already sent messages are not send // TODO in case the rendering fails, the already sent messages are not deleted
completableFutures.addAll(closeHeaderFutures); completableFutures.addAll(closeHeaderFutures);
completableFutures.addAll(self.sendMessagesToPostTarget(modMailThread, loggedMessages)); completableFutures.addAll(self.sendMessagesToPostTarget(modMailThread, loggedMessages));
return new CompletableFutureList<>(completableFutures); return new CompletableFutureList<>(completableFutures);
@@ -625,6 +655,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
public List<CompletableFuture<Message>> sendMessagesToPostTarget(ModMailThread modMailThread, List<ModMailLoggedMessageModel> loadedMessages) { public List<CompletableFuture<Message>> sendMessagesToPostTarget(ModMailThread modMailThread, List<ModMailLoggedMessageModel> loadedMessages) {
List<CompletableFuture<Message>> messageFutures = new ArrayList<>(); List<CompletableFuture<Message>> messageFutures = new ArrayList<>();
loadedMessages.forEach(message -> { loadedMessages.forEach(message -> {
log.trace("Sending message {} of modmail thread {} to modmail log post target.", modMailThread.getId(), message.getMessage().getId());
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_logged_message", message); MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_close_logged_message", message);
List<CompletableFuture<Message>> logFuture = postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_LOG, modMailThread.getServer().getId()); List<CompletableFuture<Message>> logFuture = postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_LOG, modMailThread.getServer().getId());
messageFutures.addAll(logFuture); messageFutures.addAll(logFuture);
@@ -645,6 +676,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId); Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
if(modMailThreadOpt.isPresent()) { if(modMailThreadOpt.isPresent()) {
ModMailThread modMailThread = modMailThreadOpt.get(); ModMailThread modMailThread = modMailThreadOpt.get();
log.trace("Adding (anonymous: {}) message {} of moderator to modmail thread {} and setting state to {}.", anonymous, message.getId(), modMailThreadId, ModMailThreadState.MOD_REPLIED);
modMailMessageManagementService.addMessageToThread(modMailThread, message, moderator, anonymous, true); modMailMessageManagementService.addMessageToThread(modMailThread, message, moderator, anonymous, true);
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.MOD_REPLIED); modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.MOD_REPLIED);
} else { } else {

View File

@@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.modmail.models.database.ModMailMessage; import dev.sheldan.abstracto.modmail.models.database.ModMailMessage;
import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
import dev.sheldan.abstracto.modmail.repository.ModMailMessageRepository; import dev.sheldan.abstracto.modmail.repository.ModMailMessageRepository;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -11,6 +12,7 @@ import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@Component @Component
@Slf4j
public class ModMailMessageManagementServiceBean implements ModMailMessageManagementService { public class ModMailMessageManagementServiceBean implements ModMailMessageManagementService {
@Autowired @Autowired
@@ -26,6 +28,8 @@ public class ModMailMessageManagementServiceBean implements ModMailMessageManage
.threadReference(modMailThread) .threadReference(modMailThread)
.anonymous(anonymous) .anonymous(anonymous)
.build(); .build();
log.info("Storing modmail thread message {} to modmail thread {} of user {} in server {}.",
message.getId(), modMailThread.getId(), author.getUserReference().getId(), author.getServerReference().getId());
modMailMessageRepository.save(modMailMessage); modMailMessageRepository.save(modMailMessage);
return modMailMessage; return modMailMessage;

View File

@@ -4,30 +4,33 @@ import dev.sheldan.abstracto.core.models.database.ARole;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.modmail.models.database.ModMailRole; import dev.sheldan.abstracto.modmail.models.database.ModMailRole;
import dev.sheldan.abstracto.modmail.repository.ModMailRoleRepository; import dev.sheldan.abstracto.modmail.repository.ModMailRoleRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@Component @Component
@Slf4j
public class ModMailRoleManagementServiceBean implements ModMailRoleManagementService { public class ModMailRoleManagementServiceBean implements ModMailRoleManagementService {
@Autowired @Autowired
private ModMailRoleRepository modMailRoleRepository; private ModMailRoleRepository modMailRoleRepository;
@Override @Override
public void addRoleToModMailRoles(ARole role, AServer server) { public void addRoleToModMailRoles(ARole role) {
ModMailRole roleToAdd = ModMailRole ModMailRole roleToAdd = ModMailRole
.builder() .builder()
.role(role) .role(role)
.server(server) .server(role.getServer())
.build(); .build();
log.info("Adding role {} in server {} to modmail roles.", role.getId(), role.getServer());
modMailRoleRepository.save(roleToAdd); modMailRoleRepository.save(roleToAdd);
} }
@Override @Override
public void removeRoleFromModMailRoles(ARole role, AServer server) { public void removeRoleFromModMailRoles(ARole role) {
modMailRoleRepository.deleteByServerAndRole(server, role); modMailRoleRepository.deleteByServerAndRole(role.getServer(), role);
} }
@Override @Override
@@ -36,7 +39,7 @@ public class ModMailRoleManagementServiceBean implements ModMailRoleManagementSe
} }
@Override @Override
public boolean isRoleAlreadyAssigned(ARole role, AServer server) { public boolean isRoleAlreadyAssigned(ARole role) {
return modMailRoleRepository.existsByServerAndRole(server, role); return modMailRoleRepository.existsByServerAndRole(role.getServer(), role);
} }
} }

View File

@@ -4,12 +4,14 @@ import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
import dev.sheldan.abstracto.modmail.models.database.ModMailThreadSubscriber; import dev.sheldan.abstracto.modmail.models.database.ModMailThreadSubscriber;
import dev.sheldan.abstracto.modmail.repository.ModMailSubscriberRepository; import dev.sheldan.abstracto.modmail.repository.ModMailSubscriberRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@Component @Component
@Slf4j
public class ModMailSubscriberManagementServiceBean implements ModMailSubscriberManagementService { public class ModMailSubscriberManagementServiceBean implements ModMailSubscriberManagementService {
@Autowired @Autowired
@@ -34,12 +36,16 @@ public class ModMailSubscriberManagementServiceBean implements ModMailSubscriber
.threadReference(modMailThread) .threadReference(modMailThread)
.build(); .build();
log.info("Creating subscription for user {} in server {} for modmail thread {}.",
aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId(), modMailThread.getId());
modMailSubscriberRepository.save(subscriber); modMailSubscriberRepository.save(subscriber);
return subscriber; return subscriber;
} }
@Override @Override
public void removeSubscriber(AUserInAServer aUserInAServer, ModMailThread modMailThread) { public void removeSubscriber(AUserInAServer aUserInAServer, ModMailThread modMailThread) {
log.info("Un-subscribing user {} in server {} from modmail thread {}.",
aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId(), modMailThread.getId());
modMailSubscriberRepository.deleteBySubscriberAndThreadReference(aUserInAServer, modMailThread); modMailSubscriberRepository.deleteBySubscriberAndThreadReference(aUserInAServer, modMailThread);
} }
} }

View File

@@ -7,6 +7,7 @@ import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.modmail.models.database.ModMailThread; import dev.sheldan.abstracto.modmail.models.database.ModMailThread;
import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState; import dev.sheldan.abstracto.modmail.models.database.ModMailThreadState;
import dev.sheldan.abstracto.modmail.repository.ModMailThreadRepository; import dev.sheldan.abstracto.modmail.repository.ModMailThreadRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -15,6 +16,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component @Component
@Slf4j
public class ModMailThreadManagementServiceBean implements ModMailThreadManagementService { public class ModMailThreadManagementServiceBean implements ModMailThreadManagementService {
@Autowired @Autowired
@@ -92,6 +94,9 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme
.updated(Instant.now()) .updated(Instant.now())
.build(); .build();
log.info("Create modmail thread in channel {} for user {} in server {}.",
channel.getId(), userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
modMailThreadRepository.save(thread); modMailThreadRepository.save(thread);
return thread; return thread;
} }

View File

@@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.interactive.DelayedAction;
import dev.sheldan.abstracto.core.interactive.DelayedActionConfig; import dev.sheldan.abstracto.core.interactive.DelayedActionConfig;
import dev.sheldan.abstracto.core.service.ConfigService; import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean; import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -11,6 +12,7 @@ import org.springframework.stereotype.Component;
* This delayed action is responsible for setting the system configuration of the mod mail category for a given server * This delayed action is responsible for setting the system configuration of the mod mail category for a given server
*/ */
@Component @Component
@Slf4j
public class ModMailCategoryDelayedAction implements DelayedAction { public class ModMailCategoryDelayedAction implements DelayedAction {
@Autowired @Autowired
@@ -25,6 +27,7 @@ public class ModMailCategoryDelayedAction implements DelayedAction {
@Override @Override
public void execute(DelayedActionConfig delayedActionConfig) { public void execute(DelayedActionConfig delayedActionConfig) {
ModMailCategoryDelayedActionConfig concrete = (ModMailCategoryDelayedActionConfig) delayedActionConfig; ModMailCategoryDelayedActionConfig concrete = (ModMailCategoryDelayedActionConfig) delayedActionConfig;
log.info("Executing delayed action for configuration the mdomail category to {} in server {}.", concrete.getCategoryId(), concrete.getServerId());
configService.setLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, concrete.getServerId(), concrete.getCategoryId()); configService.setLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, concrete.getServerId(), concrete.getCategoryId());
} }

View File

@@ -80,9 +80,11 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
if(configManagementService.configExists(user.getGuildId(), ModMailThreadServiceBean.MODMAIL_CATEGORY)) { if(configManagementService.configExists(user.getGuildId(), ModMailThreadServiceBean.MODMAIL_CATEGORY)) {
Guild guild = botService.getGuildByIdNullable(user.getGuildId()); Guild guild = botService.getGuildByIdNullable(user.getGuildId());
Long categoryId = configService.getLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, user.getGuildId()); Long categoryId = configService.getLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, user.getGuildId());
log.trace("Previous modmail category exists for server {}. Loading value {}.", guild.getId(), categoryId);
Category category = guild.getCategoryById(categoryId); Category category = guild.getCategoryById(categoryId);
model.setCategory(category); model.setCategory(category);
} }
log.info("Executing mod mail category setup for server {}.", user.getGuildId());
String messageText = templateService.renderTemplate(messageTemplateKey, model); String messageText = templateService.renderTemplate(messageTemplateKey, model);
AChannel channel = channelManagementService.loadChannel(user.getChannelId()); AChannel channel = channelManagementService.loadChannel(user.getChannelId());
CompletableFuture<SetupStepResult> future = new CompletableFuture<>(); CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
@@ -96,6 +98,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
Message message = event.getMessage(); Message message = event.getMessage();
// this checks whether or not the user wanted to cancel the setup // this checks whether or not the user wanted to cancel the setup
if(checkForExit(message)) { if(checkForExit(message)) {
log.info("User {} wants to exit modmail category setup for server {}.", user.getUserId(), user.getGuildId());
result = SetupStepResult.fromCancelled(); result = SetupStepResult.fromCancelled();
} else { } else {
String messageContent = event.getMessage().getContentRaw(); String messageContent = event.getMessage().getContentRaw();
@@ -106,6 +109,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
// directly validate whether or not the given category ID is a valid value // directly validate whether or not the given category ID is a valid value
modMailFeatureValidator.validateModMailCategory(featureValidationResult, guild, categoryId); modMailFeatureValidator.validateModMailCategory(featureValidationResult, guild, categoryId);
if(Boolean.TRUE.equals(featureValidationResult.getValidationResult())) { if(Boolean.TRUE.equals(featureValidationResult.getValidationResult())) {
log.trace("Given category {} maps to a valid category in server {}.", categoryId, guild.getId());
ModMailCategoryDelayedActionConfig build = ModMailCategoryDelayedActionConfig ModMailCategoryDelayedActionConfig build = ModMailCategoryDelayedActionConfig
.builder() .builder()
.serverId(user.getGuildId()) .serverId(user.getGuildId())

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.service.ConfigService;
import dev.sheldan.abstracto.core.service.FeatureValidatorService; import dev.sheldan.abstracto.core.service.FeatureValidatorService;
import dev.sheldan.abstracto.modmail.models.template.ModMailCategoryValidationErrorModel; import dev.sheldan.abstracto.modmail.models.template.ModMailCategoryValidationErrorModel;
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean; import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Category; import net.dv8tion.jda.api.entities.Category;
import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.Guild;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -21,6 +22,7 @@ import java.util.Optional;
* are used to fully validate the mod mail feature. * are used to fully validate the mod mail feature.
*/ */
@Component @Component
@Slf4j
public class ModMailFeatureValidatorBean implements ModMailFeatureValidator { public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
@Autowired @Autowired
@@ -44,7 +46,9 @@ public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
if(guildById.isPresent()) { if(guildById.isPresent()) {
Guild guild = guildById.get(); Guild guild = guildById.get();
boolean checkSucceeded = featureValidatorService.checkSystemConfig(ModMailThreadServiceBean.MODMAIL_CATEGORY, server, validationResult); boolean checkSucceeded = featureValidatorService.checkSystemConfig(ModMailThreadServiceBean.MODMAIL_CATEGORY, server, validationResult);
log.trace("Validating the modmail category for server {}.", server.getId());
if(checkSucceeded) { if(checkSucceeded) {
log.trace("Modmail category has been set for server {}. Lets see if the category exists.", server.getId());
Long modMailCategory = configService.getLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, server.getId()); Long modMailCategory = configService.getLongValue(ModMailThreadServiceBean.MODMAIL_CATEGORY, server.getId());
validateModMailCategory(validationResult, guild, modMailCategory); validateModMailCategory(validationResult, guild, modMailCategory);
} }

View File

@@ -15,17 +15,15 @@ public interface ModMailRoleManagementService {
* Adds the given {@link ARole} to the mod mail roles of the {@link AServer}. This method does not check if the role * Adds the given {@link ARole} to the mod mail roles of the {@link AServer}. This method does not check if the role
* is already present. * is already present.
* @param role The {@link ARole} to add to the mod mail roles * @param role The {@link ARole} to add to the mod mail roles
* @param server The {@link AServer} to which the given {@link ARole} should be added to the mod mail roles
*/ */
void addRoleToModMailRoles(ARole role, AServer server); void addRoleToModMailRoles(ARole role);
/** /**
* Removes the given {@link ARole} from the mod mail roles of the given {@link AServer}. Does nothing if the * Removes the given {@link ARole} from the mod mail roles of the given {@link AServer}. Does nothing if the
* role is not used as a mod mail role on the server * role is not used as a mod mail role on the server
* @param role The {@link ARole} to remove from the mod mail roles * @param role The {@link ARole} to remove from the mod mail roles
* @param server The {@link AServer} from which the role should be removed from the mod mail roles
*/ */
void removeRoleFromModMailRoles(ARole role, AServer server); void removeRoleFromModMailRoles(ARole role);
/** /**
* Retrieves all roles which should be pinged when a new mod mail thread is created by a user and returns the list * Retrieves all roles which should be pinged when a new mod mail thread is created by a user and returns the list
@@ -38,8 +36,7 @@ public interface ModMailRoleManagementService {
/** /**
* Checks whether or not the given {@link ARole} has already been assigned as a {@link ModMailRole} in the given {@link AServer} * Checks whether or not the given {@link ARole} has already been assigned as a {@link ModMailRole} in the given {@link AServer}
* @param role The {@link ARole} to check for * @param role The {@link ARole} to check for
* @param server The {@link AServer} to check in
* @return Whether or not the given {@link ARole} is used as a {@link ModMailRole} in the given {@link AServer} * @return Whether or not the given {@link ARole} is used as a {@link ModMailRole} in the given {@link AServer}
*/ */
boolean isRoleAlreadyAssigned(ARole role, AServer server); boolean isRoleAlreadyAssigned(ARole role);
} }

View File

@@ -13,6 +13,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature; import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.template.commands.serverinfo.ServerInfoModel; import dev.sheldan.abstracto.utility.models.template.commands.serverinfo.ServerInfoModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -21,6 +22,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j
public class ServerInfo extends AbstractConditionableCommand { public class ServerInfo extends AbstractConditionableCommand {
@Autowired @Autowired
@@ -30,6 +32,7 @@ public class ServerInfo extends AbstractConditionableCommand {
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
ServerInfoModel model = (ServerInfoModel) ContextConverter.fromCommandContext(commandContext, ServerInfoModel.class); ServerInfoModel model = (ServerInfoModel) ContextConverter.fromCommandContext(commandContext, ServerInfoModel.class);
model.setGuild(commandContext.getGuild()); model.setGuild(commandContext.getGuild());
log.info("Displaying serverinfo for server {}", commandContext.getGuild().getId());
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel("serverinfo_response", model, commandContext.getChannel())) return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel("serverinfo_response", model, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }

View File

@@ -13,6 +13,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature; import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.template.commands.ShowAvatarModel; import dev.sheldan.abstracto.utility.models.template.commands.ShowAvatarModel;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -22,6 +23,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j
public class ShowAvatar extends AbstractConditionableCommand { public class ShowAvatar extends AbstractConditionableCommand {
public static final String SHOW_AVATAR_RESPONSE_TEMPLATE = "showAvatar_response"; public static final String SHOW_AVATAR_RESPONSE_TEMPLATE = "showAvatar_response";
@@ -34,6 +36,8 @@ public class ShowAvatar extends AbstractConditionableCommand {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
Member memberToShow = parameters.size() == 1 ? (Member) parameters.get(0) : commandContext.getUserInitiatedContext().getMember(); Member memberToShow = parameters.size() == 1 ? (Member) parameters.get(0) : commandContext.getUserInitiatedContext().getMember();
ShowAvatarModel model = (ShowAvatarModel) ContextConverter.fromCommandContext(commandContext, ShowAvatarModel.class); ShowAvatarModel model = (ShowAvatarModel) ContextConverter.fromCommandContext(commandContext, ShowAvatarModel.class);
log.info("Showing avatar for member {} towards user {} in channel {} in server {}.",
memberToShow.getId(), commandContext.getAuthor().getId(), commandContext.getChannel().getId(), commandContext.getGuild().getId());
model.setMemberInfo(memberToShow); model.setMemberInfo(memberToShow);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SHOW_AVATAR_RESPONSE_TEMPLATE, model, commandContext.getChannel())) return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SHOW_AVATAR_RESPONSE_TEMPLATE, model, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());

View File

@@ -14,6 +14,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature; import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.template.commands.UserInfoModel; import dev.sheldan.abstracto.utility.models.template.commands.UserInfoModel;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -24,6 +25,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j
public class UserInfo extends AbstractConditionableCommand { public class UserInfo extends AbstractConditionableCommand {
@Autowired @Autowired
@@ -42,6 +44,7 @@ public class UserInfo extends AbstractConditionableCommand {
Member memberToShow = parameters.size() == 1 ? (Member) parameters.get(0) : commandContext.getAuthor(); Member memberToShow = parameters.size() == 1 ? (Member) parameters.get(0) : commandContext.getAuthor();
UserInfoModel model = (UserInfoModel) ContextConverter.slimFromCommandContext(commandContext, UserInfoModel.class); UserInfoModel model = (UserInfoModel) ContextConverter.slimFromCommandContext(commandContext, UserInfoModel.class);
if(!memberToShow.hasTimeJoined()) { if(!memberToShow.hasTimeJoined()) {
log.info("Force reloading member {} in guild {} for user info.", memberToShow.getId(), memberToShow.getGuild().getId());
return botService.forceReloadMember(memberToShow).thenCompose(member -> { return botService.forceReloadMember(memberToShow).thenCompose(member -> {
model.setMemberInfo(member); model.setMemberInfo(member);
return self.sendResponse(commandContext, model) return self.sendResponse(commandContext, model)

View File

@@ -14,6 +14,7 @@ import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.database.Reminder; import dev.sheldan.abstracto.utility.models.database.Reminder;
import dev.sheldan.abstracto.utility.models.template.commands.reminder.ReminderModel; import dev.sheldan.abstracto.utility.models.template.commands.reminder.ReminderModel;
import dev.sheldan.abstracto.utility.service.ReminderService; import dev.sheldan.abstracto.utility.service.ReminderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -23,6 +24,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j
public class Remind extends AbstractConditionableCommand { public class Remind extends AbstractConditionableCommand {
public static final String REMINDER_EMBED_KEY = "remind_response"; public static final String REMINDER_EMBED_KEY = "remind_response";
@@ -45,6 +47,8 @@ public class Remind extends AbstractConditionableCommand {
Reminder createdReminder = remindService.createReminderInForUser(aUserInAServer, text, remindTime, commandContext.getMessage()); Reminder createdReminder = remindService.createReminderInForUser(aUserInAServer, text, remindTime, commandContext.getMessage());
remindModel.setReminder(createdReminder); remindModel.setReminder(createdReminder);
log.info("Notifying user {} about reminder being scheduled.", commandContext.getAuthor().getId());
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(REMINDER_EMBED_KEY, remindModel, commandContext.getChannel())) return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(REMINDER_EMBED_KEY, remindModel, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }

View File

@@ -8,12 +8,14 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ContextConverter; import dev.sheldan.abstracto.core.command.execution.ContextConverter;
import dev.sheldan.abstracto.core.config.FeatureEnum; import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.core.utils.FutureUtils; import dev.sheldan.abstracto.core.utils.FutureUtils;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature; import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.database.Reminder; import dev.sheldan.abstracto.utility.models.database.Reminder;
import dev.sheldan.abstracto.utility.models.template.commands.reminder.RemindersModel; import dev.sheldan.abstracto.utility.models.template.commands.reminder.RemindersModel;
import dev.sheldan.abstracto.utility.service.management.ReminderManagementService; import dev.sheldan.abstracto.utility.service.management.ReminderManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -21,6 +23,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j
public class Reminders extends AbstractConditionableCommand { public class Reminders extends AbstractConditionableCommand {
public static final String REMINDERS_RESPONSE_TEMPLATE = "reminders_response"; public static final String REMINDERS_RESPONSE_TEMPLATE = "reminders_response";
@@ -33,9 +36,11 @@ public class Reminders extends AbstractConditionableCommand {
@Override @Override
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) { public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
List<Reminder> activeReminders = reminderManagementService.getActiveRemindersForUser(commandContext.getUserInitiatedContext().getAUserInAServer()); AUserInAServer aUserInAServer = commandContext.getUserInitiatedContext().getAUserInAServer();
List<Reminder> activeReminders = reminderManagementService.getActiveRemindersForUser(aUserInAServer);
RemindersModel model = (RemindersModel) ContextConverter.fromCommandContext(commandContext, RemindersModel.class); RemindersModel model = (RemindersModel) ContextConverter.fromCommandContext(commandContext, RemindersModel.class);
model.setReminders(activeReminders); model.setReminders(activeReminders);
log.info("Showing {} reminders for user {} in server {}.", activeReminders.size(), commandContext.getAuthor().getId(), commandContext.getGuild().getId());
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(REMINDERS_RESPONSE_TEMPLATE, model, commandContext.getChannel())) return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(REMINDERS_RESPONSE_TEMPLATE, model, commandContext.getChannel()))
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());
} }

View File

@@ -12,6 +12,7 @@ import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature; import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.template.commands.SuggestionLog; import dev.sheldan.abstracto.utility.models.template.commands.SuggestionLog;
import dev.sheldan.abstracto.utility.service.SuggestionService; import dev.sheldan.abstracto.utility.service.SuggestionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -21,6 +22,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j
public class Accept extends AbstractConditionableCommand { public class Accept extends AbstractConditionableCommand {
@Autowired @Autowired
@@ -32,6 +34,7 @@ public class Accept extends AbstractConditionableCommand {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
Long suggestionId = (Long) parameters.get(0); Long suggestionId = (Long) parameters.get(0);
String text = parameters.size() == 2 ? (String) parameters.get(1) : ""; String text = parameters.size() == 2 ? (String) parameters.get(1) : "";
log.trace("Using default reason for accept: {}.", parameters.size() != 2);
SuggestionLog suggestionModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class); SuggestionLog suggestionModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class);
return suggestionService.acceptSuggestion(suggestionId, text, suggestionModel) return suggestionService.acceptSuggestion(suggestionId, text, suggestionModel)
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());

View File

@@ -12,6 +12,7 @@ import dev.sheldan.abstracto.core.config.FeatureEnum;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature; import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.template.commands.SuggestionLog; import dev.sheldan.abstracto.utility.models.template.commands.SuggestionLog;
import dev.sheldan.abstracto.utility.service.SuggestionService; import dev.sheldan.abstracto.utility.service.SuggestionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -21,6 +22,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@Component @Component
@Slf4j
public class Reject extends AbstractConditionableCommand { public class Reject extends AbstractConditionableCommand {
@Autowired @Autowired
@@ -32,6 +34,7 @@ public class Reject extends AbstractConditionableCommand {
List<Object> parameters = commandContext.getParameters().getParameters(); List<Object> parameters = commandContext.getParameters().getParameters();
Long suggestionId = (Long) parameters.get(0); Long suggestionId = (Long) parameters.get(0);
String text = parameters.size() == 2 ? (String) parameters.get(1) : ""; String text = parameters.size() == 2 ? (String) parameters.get(1) : "";
log.trace("Using default reason for accept: {}.", parameters.size() != 2);
SuggestionLog suggestionModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class); SuggestionLog suggestionModel = (SuggestionLog) ContextConverter.fromCommandContext(commandContext, SuggestionLog.class);
return suggestionService.rejectSuggestion(suggestionId, text, suggestionModel) return suggestionService.rejectSuggestion(suggestionId, text, suggestionModel)
.thenApply(aVoid -> CommandResult.fromSuccess()); .thenApply(aVoid -> CommandResult.fromSuccess());

View File

@@ -24,7 +24,7 @@ public class ReminderJob extends QuartzJobBean {
@Override @Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException { protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try { try {
log.info("executing reminder job for reminder {}", reminderId); log.info("Executing reminder job for reminder {}", reminderId);
reminderService.executeReminder(reminderId); reminderService.executeReminder(reminderId);
} catch (Exception e) { } catch (Exception e) {
log.error("Reminder job failed to execute.", e); log.error("Reminder job failed to execute.", e);

View File

@@ -39,14 +39,17 @@ public class MessageEmbedListener implements MessageReceivedListener {
String messageRaw = message.getContentRaw(); String messageRaw = message.getContentRaw();
List<MessageEmbedLink> links = messageEmbedService.getLinksInMessage(messageRaw); List<MessageEmbedLink> links = messageEmbedService.getLinksInMessage(messageRaw);
if(!links.isEmpty()) { if(!links.isEmpty()) {
log.trace("We found {} links to embed in message {} in channel {} in guild {}.", links.size(), message.getId(), message.getChannel().getId(), message.getGuild().getId());
Long userEmbeddingUserInServerId = userInServerManagementService.loadUser(message.getMember()).getUserInServerId(); Long userEmbeddingUserInServerId = userInServerManagementService.loadUser(message.getMember()).getUserInServerId();
for (MessageEmbedLink messageEmbedLink : links) { for (MessageEmbedLink messageEmbedLink : links) {
if(!messageEmbedLink.getServerId().equals(message.getGuild().getIdLong())) { if(!messageEmbedLink.getServerId().equals(message.getGuild().getIdLong())) {
log.info("Link for message {} was from a foreign server {}. Do not embed.", messageEmbedLink.getMessageId(), messageEmbedLink.getServerId());
continue; continue;
} }
messageRaw = messageRaw.replace(messageEmbedLink.getWholeUrl(), ""); messageRaw = messageRaw.replace(messageEmbedLink.getWholeUrl(), "");
Consumer<CachedMessage> cachedMessageConsumer = cachedMessage ->self.loadUserAndEmbed(message, userEmbeddingUserInServerId, cachedMessage); Consumer<CachedMessage> cachedMessageConsumer = cachedMessage ->self.loadUserAndEmbed(message, userEmbeddingUserInServerId, cachedMessage);
messageCache.getMessageFromCache(messageEmbedLink.getServerId(), messageEmbedLink.getChannelId(), messageEmbedLink.getMessageId()).thenAccept(cachedMessageConsumer) messageCache.getMessageFromCache(messageEmbedLink.getServerId(), messageEmbedLink.getChannelId(), messageEmbedLink.getMessageId())
.thenAccept(cachedMessageConsumer)
.exceptionally(throwable -> { .exceptionally(throwable -> {
log.error("Error when embedding link for message {}", message.getId(), throwable); log.error("Error when embedding link for message {}", message.getId(), throwable);
return null; return null;
@@ -60,6 +63,8 @@ public class MessageEmbedListener implements MessageReceivedListener {
@Transactional @Transactional
public void loadUserAndEmbed(Message message, Long cause, CachedMessage cachedMessage) { public void loadUserAndEmbed(Message message, Long cause, CachedMessage cachedMessage) {
log.info("Embedding link to message {} in channel {} in server {} to channel {} and server {}.",
cachedMessage.getMessageId(), cachedMessage.getChannelId(), cachedMessage.getServerId(), message.getChannel().getId(), message.getGuild().getId());
messageEmbedService.embedLink(cachedMessage, message.getTextChannel(), cause , message); messageEmbedService.embedLink(cachedMessage, message.getTextChannel(), cause , message);
} }

View File

@@ -13,7 +13,6 @@ import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.database.EmbeddedMessage; import dev.sheldan.abstracto.utility.models.database.EmbeddedMessage;
import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManagementService; import dev.sheldan.abstracto.utility.service.management.MessageEmbedPostManagementService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.MessageReaction; import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent; import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -45,8 +44,6 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener
Long guildId = message.getServerId(); Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(REMOVAL_EMOTE, guildId); AEmote aEmote = emoteService.getEmoteOrDefaultEmote(REMOVAL_EMOTE, guildId);
MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote(); MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote();
Optional<Emote> emoteInGuild = botService.getEmote(guildId, aEmote);
log.trace("Removing embed in message {} in channel {} in server {} because of a user reaction.", message.getMessageId(), message.getChannelId(), message.getServerId());
if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) { if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) {
Optional<EmbeddedMessage> embeddedMessageOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId()); Optional<EmbeddedMessage> embeddedMessageOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId());
if(embeddedMessageOptional.isPresent()) { if(embeddedMessageOptional.isPresent()) {
@@ -55,12 +52,18 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener
if(embeddedMessage.getEmbeddedUser().getUserReference().getId().equals(userReacting.getId()) if(embeddedMessage.getEmbeddedUser().getUserReference().getId().equals(userReacting.getId())
|| embeddedMessage.getEmbeddingUser().getUserReference().getId().equals(userReacting.getId()) || embeddedMessage.getEmbeddingUser().getUserReference().getId().equals(userReacting.getId())
) { ) {
log.info("Removing embed in message {} in channel {} in server {} because of a user reaction.", message.getMessageId(), message.getChannelId(), message.getServerId());
messageService.deleteMessageInChannelInServer(message.getServerId(), message.getChannelId(), message.getMessageId()).thenAccept(aVoid ->{ messageService.deleteMessageInChannelInServer(message.getServerId(), message.getChannelId(), message.getMessageId()).thenAccept(aVoid ->{
Optional<EmbeddedMessage> innerOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId()); Optional<EmbeddedMessage> innerOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId());
innerOptional.ifPresent(value -> messageEmbedPostManagementService.deleteEmbeddedMessage(value)); innerOptional.ifPresent(value -> messageEmbedPostManagementService.deleteEmbeddedMessage(value));
}); });
} else {
log.trace("Somebody besides the original author and the user embedding added the removal reaction to the message {} in channel {} in server {}.",
message.getMessageId(), message.getChannelId(), message.getServerId());
} }
} else {
log.trace("Removal emote was placed on a message which was not recognized as an embedded message.");
} }
} }
} }

View File

@@ -68,7 +68,7 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId); AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId);
MessageReaction.ReactionEmote reactionEmote = addedReaction.getReactionEmote(); MessageReaction.ReactionEmote reactionEmote = addedReaction.getReactionEmote();
if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) { if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) {
log.trace("User {} in server {} reacted with star to put a message {} on starboard.", userAdding.getUserReference().getId(), userAdding.getServerReference().getId(), message.getMessageId()); log.info("User {} in server {} reacted with star to put a message {} from channel {} on starboard.", userAdding.getUserReference().getId(), userAdding.getServerReference().getId(), message.getMessageId(), message.getChannelId());
Optional<CachedReaction> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote); Optional<CachedReaction> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
handleStarboardPostChange(message, reactionOptional.orElse(null), userAdding, true); handleStarboardPostChange(message, reactionOptional.orElse(null), userAdding, true);
} }
@@ -105,6 +105,7 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
private void updateStarboardPost(CachedMessage message, AUserInAServer userReacting, boolean adding, StarboardPost starboardPost, List<AUserInAServer> userExceptAuthor) { private void updateStarboardPost(CachedMessage message, AUserInAServer userReacting, boolean adding, StarboardPost starboardPost, List<AUserInAServer> userExceptAuthor) {
starboardPost.setIgnored(false); starboardPost.setIgnored(false);
// TODO handle futures correctly
starboardService.updateStarboardPost(starboardPost, message, userExceptAuthor); starboardService.updateStarboardPost(starboardPost, message, userExceptAuthor);
if(adding) { if(adding) {
log.trace("Adding reactor {} from message {}", userReacting.getUserReference().getId(), message.getMessageId()); log.trace("Adding reactor {} from message {}", userReacting.getUserReference().getId(), message.getMessageId());
@@ -130,7 +131,7 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId); AEmote aEmote = emoteService.getEmoteOrDefaultEmote(STAR_EMOTE, guildId);
MessageReaction.ReactionEmote reactionEmote = removedReaction.getReactionEmote(); MessageReaction.ReactionEmote reactionEmote = removedReaction.getReactionEmote();
if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) { if(emoteService.isReactionEmoteAEmote(reactionEmote, aEmote)) {
log.trace("User {} in server {} removed star reaction from message {} on starboard.", log.info("User {} in server {} removed star reaction from message {} on starboard.",
userRemoving.getUserReference().getId(), userRemoving.getServerReference().getId(), message.getMessageId()); userRemoving.getUserReference().getId(), userRemoving.getServerReference().getId(), message.getMessageId());
Optional<CachedReaction> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote); Optional<CachedReaction> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
handleStarboardPostChange(message, reactionOptional.orElse(null), userRemoving, false); handleStarboardPostChange(message, reactionOptional.orElse(null), userRemoving, false);
@@ -158,6 +159,8 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId()); Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId());
starboardPostOptional.ifPresent(starboardPost -> { starboardPostOptional.ifPresent(starboardPost -> {
log.info("Reactions on message {} in channel {} in server {} were cleared. Completely deleting the starboard post {}.",
message.getMessageId(), message.getChannelId(), message.getServerId(), starboardPost.getId());
starboardPostReactorManagementService.removeReactors(starboardPost); starboardPostReactorManagementService.removeReactors(starboardPost);
completelyRemoveStarboardPost(starboardPost); completelyRemoveStarboardPost(starboardPost);
}); });

View File

@@ -77,7 +77,7 @@ public class RemindServiceBean implements ReminderService {
user.getUserReference().getId(), user.getServerReference().getId(), remindAt); user.getUserReference().getId(), user.getServerReference().getId(), remindAt);
if(remindIn.getSeconds() < 60) { if(remindIn.getSeconds() < 60) {
log.trace("Directly scheduling the reminder, because it was below the threshold."); log.info("Directly scheduling unremind for reminder {}, because it was below the threshold.", reminder.getId());
instantReminderScheduler.schedule(() -> { instantReminderScheduler.schedule(() -> {
try { try {
self.executeReminder(reminder.getId()); self.executeReminder(reminder.getId());
@@ -86,10 +86,10 @@ public class RemindServiceBean implements ReminderService {
} }
}, remindIn.toNanos(), TimeUnit.NANOSECONDS); }, remindIn.toNanos(), TimeUnit.NANOSECONDS);
} else { } else {
log.trace("Starting scheduled job to execute reminder.");
JobDataMap parameters = new JobDataMap(); JobDataMap parameters = new JobDataMap();
parameters.putAsString("reminderId", reminder.getId()); parameters.putAsString("reminderId", reminder.getId());
String triggerKey = schedulerService.executeJobWithParametersOnce("reminderJob", "utility", parameters, Date.from(reminder.getTargetDate())); String triggerKey = schedulerService.executeJobWithParametersOnce("reminderJob", "utility", parameters, Date.from(reminder.getTargetDate()));
log.info("Starting scheduled job with trigger {} to execute reminder. {}", triggerKey, reminder.getId());
reminder.setJobTriggerKey(triggerKey); reminder.setJobTriggerKey(triggerKey);
reminderManagementService.saveReminder(reminder); reminderManagementService.saveReminder(reminder);
} }
@@ -105,7 +105,8 @@ public class RemindServiceBean implements ReminderService {
} }
AServer server = reminderToRemindFor.getServer(); AServer server = reminderToRemindFor.getServer();
AChannel channel = reminderToRemindFor.getChannel(); AChannel channel = reminderToRemindFor.getChannel();
log.info("Executing reminder {}.", reminderId); log.info("Executing reminder {} in channel {} in server {} for user {}.",
reminderId, channel.getId(), server.getId(), reminderToRemindFor.getRemindedUser().getUserReference().getId());
Optional<Guild> guildToAnswerIn = botService.getGuildById(server.getId()); Optional<Guild> guildToAnswerIn = botService.getGuildById(server.getId());
if(guildToAnswerIn.isPresent()) { if(guildToAnswerIn.isPresent()) {
Optional<TextChannel> channelToAnswerIn = botService.getTextChannelFromServerOptional(server.getId(), channel.getId()); Optional<TextChannel> channelToAnswerIn = botService.getTextChannelFromServerOptional(server.getId(), channel.getId());
@@ -133,9 +134,11 @@ public class RemindServiceBean implements ReminderService {
@Override @Override
public void unRemind(Long reminderId, AUserInAServer aUserInAServer) { public void unRemind(Long reminderId, AUserInAServer aUserInAServer) {
log.info("Trying to end reminder {} for user {} in server {}.", reminderId, aUserInAServer.getUserReference().getId(),aUserInAServer.getServerReference().getId());
Reminder reminder = reminderManagementService.getReminderByAndByUserNotReminded(aUserInAServer, reminderId).orElseThrow(() -> new ReminderNotFoundException(reminderId)); Reminder reminder = reminderManagementService.getReminderByAndByUserNotReminded(aUserInAServer, reminderId).orElseThrow(() -> new ReminderNotFoundException(reminderId));
reminder.setReminded(true); reminder.setReminded(true);
if(reminder.getJobTriggerKey() != null) { if(reminder.getJobTriggerKey() != null) {
log.trace("Stopping scheduled trigger {} for reminder {}.", reminder.getJobTriggerKey(), reminderId);
schedulerService.stopTrigger(reminder.getJobTriggerKey()); schedulerService.stopTrigger(reminder.getJobTriggerKey());
} }
} }

View File

@@ -32,7 +32,6 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -90,9 +89,8 @@ public class StarboardServiceBean implements StarboardService {
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, StarboardPostTarget.STARBOARD, message.getServerId()); List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, StarboardPostTarget.STARBOARD, message.getServerId());
Long starboardChannelId = starboard.getChannelReference().getId(); Long starboardChannelId = starboard.getChannelReference().getId();
Long starredUserId = starredUser.getUserInServerId(); Long starredUserId = starredUser.getUserInServerId();
Long userReactingId = userReacting.getUserInServerId();
CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenAccept(aVoid ->
self.persistPost(message, userExceptAuthorIds, completableFutures, starboardChannelId, starredUserId, userReactingId) self.persistPost(message, userExceptAuthorIds, completableFutures, starboardChannelId, starredUserId)
) .exceptionally(throwable -> { ) .exceptionally(throwable -> {
log.error("Failed to create starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId(), throwable); log.error("Failed to create starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId(), throwable);
return null; return null;
@@ -101,29 +99,25 @@ public class StarboardServiceBean implements StarboardService {
} }
@Transactional @Transactional
public void persistPost(CachedMessage message, List<Long> userExceptAuthorIds, List<CompletableFuture<Message>> completableFutures, Long starboardChannelId, Long starredUserId, Long userReactingId) { public void persistPost(CachedMessage message, List<Long> userExceptAuthorIds, List<CompletableFuture<Message>> completableFutures, Long starboardChannelId, Long starredUserId) {
AUserInAServer innerStarredUser = userInServerManagementService.loadUserConditional(starredUserId).orElseThrow(() -> new UserInServerNotFoundException(starredUserId)); AUserInAServer innerStarredUser = userInServerManagementService.loadUserConditional(starredUserId).orElseThrow(() -> new UserInServerNotFoundException(starredUserId));
try { AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId);
AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId); Message message1 = completableFutures.get(0).join();
Message message1 = completableFutures.get(0).get(); AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage
AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage .builder()
.builder() .messageId(message1.getIdLong())
.messageId(message1.getIdLong()) .channel(starboardChannel)
.channel(starboardChannel) .server(starboardChannel.getServer())
.server(starboardChannel.getServer()) .build();
.build(); StarboardPost starboardPost = starboardPostManagementService.createStarboardPost(message, innerStarredUser, aServerAChannelMessage);
StarboardPost starboardPost = starboardPostManagementService.createStarboardPost(message, innerStarredUser, aServerAChannelMessage); log.info("Persisting starboard post in channel {} with message {} with {} reactors.", message1.getId(),starboardChannelId, userExceptAuthorIds.size());
if(userExceptAuthorIds.isEmpty()) { if(userExceptAuthorIds.isEmpty()) {
log.warn("There are no user ids except the author for the reactions in post {} in guild {} for message {} in channel {}.", starboardPost.getId(), message.getChannelId(), message.getMessageId(), message.getChannelId()); log.warn("There are no user ids except the author for the reactions in post {} in guild {} for message {} in channel {}.", starboardPost.getId(), message.getChannelId(), message.getMessageId(), message.getChannelId());
}
userExceptAuthorIds.forEach(aLong -> {
AUserInAServer user = userInServerManagementService.loadUserConditional(aLong).orElseThrow(() -> new UserInServerNotFoundException(aLong));
starboardPostReactorManagementService.addReactor(starboardPost, user);
});
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to post messages.", e);
Thread.currentThread().interrupt();
} }
userExceptAuthorIds.forEach(aLong -> {
AUserInAServer user = userInServerManagementService.loadUserConditional(aLong).orElseThrow(() -> new UserInServerNotFoundException(aLong));
starboardPostReactorManagementService.addReactor(starboardPost, user);
});
} }
private StarboardPostModel buildStarboardPostModel(CachedMessage message, Integer starCount) { private StarboardPostModel buildStarboardPostModel(CachedMessage message, Integer starCount) {
@@ -150,20 +144,14 @@ public class StarboardServiceBean implements StarboardService {
@Override @Override
public void updateStarboardPost(StarboardPost post, CachedMessage message, List<AUserInAServer> userExceptAuthor) { public void updateStarboardPost(StarboardPost post, CachedMessage message, List<AUserInAServer> userExceptAuthor) {
log.info("Updating starboard post {} in server {} with reactors {}.", post.getId(), post.getSourceChanel().getServer().getId(), userExceptAuthor.size());
StarboardPostModel starboardPostModel = buildStarboardPostModel(message, userExceptAuthor.size()); StarboardPostModel starboardPostModel = buildStarboardPostModel(message, userExceptAuthor.size());
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARBOARD_POST_TEMPLATE, starboardPostModel); MessageToSend messageToSend = templateService.renderEmbedTemplate(STARBOARD_POST_TEMPLATE, starboardPostModel);
List<CompletableFuture<Message>> futures = postTargetService.editOrCreatedInPostTarget(post.getStarboardMessageId(), messageToSend, StarboardPostTarget.STARBOARD, message.getServerId()); List<CompletableFuture<Message>> futures = postTargetService.editOrCreatedInPostTarget(post.getStarboardMessageId(), messageToSend, StarboardPostTarget.STARBOARD, message.getServerId());
Long starboardPostId = post.getId(); Long starboardPostId = post.getId();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> { CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
try { Optional<StarboardPost> innerPost = starboardPostManagementService.findByStarboardPostId(starboardPostId);
Optional<StarboardPost> innerPost = starboardPostManagementService.findByStarboardPostId(starboardPostId); innerPost.ifPresent(starboardPost -> starboardPostManagementService.setStarboardPostMessageId(starboardPost, futures.get(0).join().getIdLong()));
if(innerPost.isPresent()) {
starboardPostManagementService.setStarboardPostMessageId(innerPost.get(), futures.get(0).get().getIdLong());
}
} catch (InterruptedException | ExecutionException e) {
log.error("Failed to post starboard post.", e);
Thread.currentThread().interrupt();
}
}).exceptionally(throwable -> { }).exceptionally(throwable -> {
log.error("Failed to update starboard post {}.", post.getId(), throwable); log.error("Failed to update starboard post {}.", post.getId(), throwable);
return null; return null;
@@ -173,6 +161,7 @@ public class StarboardServiceBean implements StarboardService {
@Override @Override
public void deleteStarboardMessagePost(StarboardPost message) { public void deleteStarboardMessagePost(StarboardPost message) {
AChannel starboardChannel = message.getStarboardChannel(); AChannel starboardChannel = message.getStarboardChannel();
log.info("Deleting starboard post {} in server {}", message.getId(), message.getSourceChanel().getServer().getId());
botService.deleteMessage(starboardChannel.getServer().getId(), starboardChannel.getId(), message.getStarboardMessageId()); botService.deleteMessage(starboardChannel.getServer().getId(), starboardChannel.getId(), message.getStarboardMessageId());
} }

View File

@@ -71,19 +71,23 @@ public class SuggestionServiceBean implements SuggestionService {
suggestionLog.setText(text); suggestionLog.setText(text);
MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_LOG_TEMPLATE, suggestionLog); MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_LOG_TEMPLATE, suggestionLog);
long guildId = member.getGuild().getIdLong(); long guildId = member.getGuild().getIdLong();
log.info("Creating suggestion with id {} in server {} from member {}.", newSuggestionId, member.getGuild().getId(), member.getId());
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, guildId); List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(messageToSend, SuggestionPostTarget.SUGGESTION, guildId);
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenCompose(aVoid -> { return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenCompose(aVoid -> {
Message message = completableFutures.get(0).join(); Message message = completableFutures.get(0).join();
log.trace("Posted message, adding reaction for suggestion {} to message {}.", newSuggestionId, message.getId());
CompletableFuture<Void> firstReaction = messageService.addReactionToMessageWithFuture(SUGGESTION_YES_EMOTE, guildId, message); CompletableFuture<Void> firstReaction = messageService.addReactionToMessageWithFuture(SUGGESTION_YES_EMOTE, guildId, message);
CompletableFuture<Void> secondReaction = messageService.addReactionToMessageWithFuture(SUGGESTION_NO_EMOTE, guildId, message); CompletableFuture<Void> secondReaction = messageService.addReactionToMessageWithFuture(SUGGESTION_NO_EMOTE, guildId, message);
return CompletableFuture.allOf(firstReaction, secondReaction).thenAccept(aVoid1 -> return CompletableFuture.allOf(firstReaction, secondReaction).thenAccept(aVoid1 -> {
self.persistSuggestionInDatabase(member, text, message, newSuggestionId) log.trace("Reaction added to message {} for suggestion {}.", message.getId(), newSuggestionId);
); self.persistSuggestionInDatabase(member, text, message, newSuggestionId);
});
}); });
} }
@Transactional @Transactional
public void persistSuggestionInDatabase(Member member, String text, Message message, Long suggestionId) { public void persistSuggestionInDatabase(Member member, String text, Message message, Long suggestionId) {
log.info("Persisting suggestion {} for server {} in database.", suggestionId, member.getGuild().getId());
suggestionManagementService.createSuggestion(member, text, message, suggestionId); suggestionManagementService.createSuggestion(member, text, message, suggestionId);
} }
@@ -91,6 +95,7 @@ public class SuggestionServiceBean implements SuggestionService {
public CompletableFuture<Void> acceptSuggestion(Long suggestionId, String text, SuggestionLog suggestionLog) { public CompletableFuture<Void> acceptSuggestion(Long suggestionId, String text, SuggestionLog suggestionLog) {
Suggestion suggestion = suggestionManagementService.getSuggestion(suggestionId).orElseThrow(() -> new SuggestionNotFoundException(suggestionId)); Suggestion suggestion = suggestionManagementService.getSuggestion(suggestionId).orElseThrow(() -> new SuggestionNotFoundException(suggestionId));
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.ACCEPTED); suggestionManagementService.setSuggestionState(suggestion, SuggestionState.ACCEPTED);
log.info("Accepting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
return updateSuggestion(text, suggestionLog, suggestion); return updateSuggestion(text, suggestionLog, suggestion);
} }
@@ -99,6 +104,7 @@ public class SuggestionServiceBean implements SuggestionService {
Long channelId = suggestion.getChannel().getId(); Long channelId = suggestion.getChannel().getId();
Long originalMessageId = suggestion.getMessageId(); Long originalMessageId = suggestion.getMessageId();
Long serverId = suggestion.getServer().getId(); Long serverId = suggestion.getServer().getId();
log.info("Updated posted suggestion {} in server {}.", suggestion.getId(), suggestion.getServer().getId());
suggestionLog.setOriginalChannelId(channelId); suggestionLog.setOriginalChannelId(channelId);
suggestionLog.setOriginalMessageId(originalMessageId); suggestionLog.setOriginalMessageId(originalMessageId);
@@ -130,6 +136,7 @@ public class SuggestionServiceBean implements SuggestionService {
public CompletableFuture<Void> updateSuggestionMessageText(String text, SuggestionLog suggestionLog, Message message) { public CompletableFuture<Void> updateSuggestionMessageText(String text, SuggestionLog suggestionLog, Message message) {
Optional<MessageEmbed> embedOptional = message.getEmbeds().stream().filter(embed -> embed.getDescription() != null).findFirst(); Optional<MessageEmbed> embedOptional = message.getEmbeds().stream().filter(embed -> embed.getDescription() != null).findFirst();
if(embedOptional.isPresent()) { if(embedOptional.isPresent()) {
log.info("Updating the text of the suggestion {} in server {}.", suggestionLog.getSuggestionId(), message.getGuild().getId());
MessageEmbed suggestionEmbed = embedOptional.get(); MessageEmbed suggestionEmbed = embedOptional.get();
suggestionLog.setReason(text); suggestionLog.setReason(text);
suggestionLog.setText(suggestionEmbed.getDescription()); suggestionLog.setText(suggestionEmbed.getDescription());
@@ -143,9 +150,10 @@ public class SuggestionServiceBean implements SuggestionService {
} }
@Override @Override
public CompletableFuture<Void> rejectSuggestion(Long suggestionId, String text, SuggestionLog log) { public CompletableFuture<Void> rejectSuggestion(Long suggestionId, String text, SuggestionLog suggestionLog) {
Suggestion suggestion = suggestionManagementService.getSuggestion(suggestionId).orElseThrow(() -> new SuggestionNotFoundException(suggestionId)); Suggestion suggestion = suggestionManagementService.getSuggestion(suggestionId).orElseThrow(() -> new SuggestionNotFoundException(suggestionId));
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.REJECTED); suggestionManagementService.setSuggestionState(suggestion, SuggestionState.REJECTED);
return updateSuggestion(text, log, suggestion); log.info("Rejecting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
return updateSuggestion(text, suggestionLog, suggestion);
} }
} }

View File

@@ -57,6 +57,10 @@ public class MessageEmbedPostManagementServiceBean implements MessageEmbedPostMa
.embeddingUser(embeddingUser) .embeddingUser(embeddingUser)
.build(); .build();
log.info("Saving embedded post: message {} by user {} in channel {} in server {} embedded message {} by user {} in channel {} in server {}.",
messageContainingEmbed.getIdLong(), embeddingUser.getUserReference().getId(), embeddingChannel.getId(), embeddingUser.getServerReference().getId(),
embeddedMessage.getMessageId(), embeddedMessage.getAuthorId(), embeddedMessage.getChannelId(), embeddedMessage.getServerId());
embeddedMessageRepository.save(messageEmbedPost); embeddedMessageRepository.save(messageEmbedPost);
} }
@@ -68,6 +72,7 @@ public class MessageEmbedPostManagementServiceBean implements MessageEmbedPostMa
@Override @Override
@Transactional @Transactional
public void deleteEmbeddedMessage(EmbeddedMessage embeddedMessage) { public void deleteEmbeddedMessage(EmbeddedMessage embeddedMessage) {
log.info("Deleting embedded message {}.", embeddedMessage.getEmbeddingMessageId());
embeddedMessageRepository.delete(embeddedMessage); embeddedMessageRepository.delete(embeddedMessage);
} }

View File

@@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.utility.models.database.Reminder; import dev.sheldan.abstracto.utility.models.database.Reminder;
import dev.sheldan.abstracto.utility.repository.ReminderRepository; import dev.sheldan.abstracto.utility.repository.ReminderRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -12,6 +13,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component @Component
@Slf4j
public class ReminderManagementServiceBean implements ReminderManagementService { public class ReminderManagementServiceBean implements ReminderManagementService {
@Autowired @Autowired
@@ -29,6 +31,8 @@ public class ReminderManagementServiceBean implements ReminderManagementService
.targetDate(timeToBeRemindedAt) .targetDate(timeToBeRemindedAt)
.messageId(messageId) .messageId(messageId)
.build(); .build();
log.info("Creating reminder for user {} in server {} in message {} to be reminded at {}.",
userToBeReminded.getAUserInAServer().getUserReference().getId(), userToBeReminded.getGuild().getId(), messageId, timeToBeRemindedAt);
reminderRepository.save(reminder); reminderRepository.save(reminder);
return reminder; return reminder;
@@ -42,6 +46,7 @@ public class ReminderManagementServiceBean implements ReminderManagementService
@Override @Override
public void setReminded(Reminder reminder) { public void setReminded(Reminder reminder) {
reminder.setReminded(true); reminder.setReminded(true);
log.info("Setting reminder {} to reminded.", reminder.getId());
reminderRepository.save(reminder); reminderRepository.save(reminder);
} }

View File

@@ -7,6 +7,7 @@ import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.management.ChannelManagementService; import dev.sheldan.abstracto.core.service.management.ChannelManagementService;
import dev.sheldan.abstracto.utility.models.database.StarboardPost; import dev.sheldan.abstracto.utility.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.repository.StarboardPostRepository; import dev.sheldan.abstracto.utility.repository.StarboardPostRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -17,6 +18,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component @Component
@Slf4j
public class StarboardPostManagementServiceBean implements StarboardPostManagementService { public class StarboardPostManagementServiceBean implements StarboardPostManagementService {
@Autowired @Autowired
@@ -38,6 +40,10 @@ public class StarboardPostManagementServiceBean implements StarboardPostManageme
.starboardChannel(starboardPost.getChannel()) .starboardChannel(starboardPost.getChannel())
.starredDate(Instant.now()) .starredDate(Instant.now())
.build(); .build();
log.info("Persisting starboard post for message {} in channel {} in server {} on starboard at message {} in channel {} and server {} of user {}.",
starredMessage.getMessageId(), starredMessage.getChannelId(), starredMessage.getServerId(),
starboardPost.getMessageId(), starboardPost.getChannel().getId(), starboardPost.getServer().getId(),
starredUser.getUserReference().getId());
repository.save(post); repository.save(post);
return post; return post;
} }

View File

@@ -7,12 +7,14 @@ import dev.sheldan.abstracto.utility.models.template.commands.starboard.StarStat
import dev.sheldan.abstracto.utility.repository.StarStatsUserResult; import dev.sheldan.abstracto.utility.repository.StarStatsUserResult;
import dev.sheldan.abstracto.utility.repository.StarboardPostReactionRepository; import dev.sheldan.abstracto.utility.repository.StarboardPostReactionRepository;
import dev.sheldan.abstracto.utility.repository.converter.StarStatsUserConverter; import dev.sheldan.abstracto.utility.repository.converter.StarStatsUserConverter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@Component @Component
@Slf4j
public class StarboardPostReactorManagementServiceBean implements StarboardPostReactorManagementService { public class StarboardPostReactorManagementServiceBean implements StarboardPostReactorManagementService {
@Autowired @Autowired
@@ -28,16 +30,19 @@ public class StarboardPostReactorManagementServiceBean implements StarboardPostR
.starboardPost(post) .starboardPost(post)
.reactor(user) .reactor(user)
.build(); .build();
log.info("Persisting the reactor {} for starboard post {} in server {}.", user.getUserReference().getId(), post.getId(), user.getServerReference().getId());
repository.save(reactor); repository.save(reactor);
} }
@Override @Override
public void removeReactor(StarboardPost post, AUserInAServer user) { public void removeReactor(StarboardPost post, AUserInAServer user) {
log.info("Removing reactor {} from post {} in server {}.", user.getUserReference().getId(), post.getId(), user.getServerReference().getId());
repository.deleteByReactorAndStarboardPost(user, post); repository.deleteByReactorAndStarboardPost(user, post);
} }
@Override @Override
public void removeReactors(StarboardPost post) { public void removeReactors(StarboardPost post) {
log.info("Removing all {} reactors from starboard post {}", post.getReactions().size(), post.getId());
repository.deleteByStarboardPost(post); repository.deleteByStarboardPost(post);
} }

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.utility.models.database.Suggestion; import dev.sheldan.abstracto.utility.models.database.Suggestion;
import dev.sheldan.abstracto.utility.models.SuggestionState; import dev.sheldan.abstracto.utility.models.SuggestionState;
import dev.sheldan.abstracto.utility.repository.SuggestionRepository; import dev.sheldan.abstracto.utility.repository.SuggestionRepository;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -17,6 +18,7 @@ import java.time.Instant;
import java.util.Optional; import java.util.Optional;
@Component @Component
@Slf4j
public class SuggestionManagementServiceBean implements SuggestionManagementService { public class SuggestionManagementServiceBean implements SuggestionManagementService {
@Autowired @Autowired
@@ -51,6 +53,8 @@ public class SuggestionManagementServiceBean implements SuggestionManagementServ
.channel(channel) .channel(channel)
.messageId(message.getIdLong()) .messageId(message.getIdLong())
.build(); .build();
log.info("Persisting suggestion {} at message {} in channel {} on server {} from user {}.",
suggestionId, message.getId(), channelId, message.getGuild().getId(), suggester.getUserReference().getId());
suggestionRepository.save(suggestion); suggestionRepository.save(suggestion);
return suggestion; return suggestion;
} }
@@ -64,6 +68,7 @@ public class SuggestionManagementServiceBean implements SuggestionManagementServ
@Override @Override
public void setSuggestionState(Suggestion suggestion, SuggestionState newState) { public void setSuggestionState(Suggestion suggestion, SuggestionState newState) {
suggestion.setState(newState); suggestion.setState(newState);
log.info("Setting suggestion {} to state {}.", suggestion.getId(), newState);
suggestionRepository.save(suggestion); suggestionRepository.save(suggestion);
} }
} }

View File

@@ -7,10 +7,12 @@ import dev.sheldan.abstracto.core.service.FeatureValidatorService;
import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService; import dev.sheldan.abstracto.core.service.management.DefaultConfigManagementService;
import dev.sheldan.abstracto.utility.StarboardFeatureValidator; import dev.sheldan.abstracto.utility.StarboardFeatureValidator;
import dev.sheldan.abstracto.utility.service.StarboardServiceBean; import dev.sheldan.abstracto.utility.service.StarboardServiceBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@Slf4j
public class StarboardFeatureValidatorService implements StarboardFeatureValidator { public class StarboardFeatureValidatorService implements StarboardFeatureValidator {
@Autowired @Autowired
@@ -22,6 +24,7 @@ public class StarboardFeatureValidatorService implements StarboardFeatureValidat
@Override @Override
public void featureIsSetup(FeatureConfig featureConfig, AServer server, FeatureValidationResult validationResult) { public void featureIsSetup(FeatureConfig featureConfig, AServer server, FeatureValidationResult validationResult) {
int levelAmount = defaultConfigManagementService.getDefaultConfig(StarboardServiceBean.STAR_LEVELS_CONFIG_KEY).getLongValue().intValue(); int levelAmount = defaultConfigManagementService.getDefaultConfig(StarboardServiceBean.STAR_LEVELS_CONFIG_KEY).getLongValue().intValue();
log.info("Validating starboard feature for server {}.", server.getId());
for(int i = 1; i <= levelAmount; i++) { for(int i = 1; i <= levelAmount; i++) {
featureValidatorService.checkSystemConfig("starLvl" + i, server, validationResult); featureValidatorService.checkSystemConfig("starLvl" + i, server, validationResult);
} }

View File

@@ -8,6 +8,7 @@ import dev.sheldan.abstracto.core.service.ChannelService;
import dev.sheldan.abstracto.test.command.CommandConfigValidator; import dev.sheldan.abstracto.test.command.CommandConfigValidator;
import dev.sheldan.abstracto.test.command.CommandTestUtilities; import dev.sheldan.abstracto.test.command.CommandTestUtilities;
import dev.sheldan.abstracto.utility.models.template.commands.UserInfoModel; import dev.sheldan.abstracto.utility.models.template.commands.UserInfoModel;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@@ -60,6 +61,7 @@ public class UserInfoTest {
CommandContext noParameters = CommandTestUtilities.getNoParameters(); CommandContext noParameters = CommandTestUtilities.getNoParameters();
when(noParameters.getAuthor().hasTimeJoined()).thenReturn(false); when(noParameters.getAuthor().hasTimeJoined()).thenReturn(false);
Member loadedAuthor = Mockito.mock(Member.class); Member loadedAuthor = Mockito.mock(Member.class);
when(noParameters.getAuthor().getGuild()).thenReturn(Mockito.mock(Guild.class));
when(botService.forceReloadMember(noParameters.getAuthor())).thenReturn(CompletableFuture.completedFuture(loadedAuthor)); when(botService.forceReloadMember(noParameters.getAuthor())).thenReturn(CompletableFuture.completedFuture(loadedAuthor));
when(self.sendResponse(eq(noParameters), modelArgumentCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null)); when(self.sendResponse(eq(noParameters), modelArgumentCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(noParameters); CompletableFuture<CommandResult> result = testUnit.executeAsync(noParameters);
@@ -86,6 +88,7 @@ public class UserInfoTest {
when(member.hasTimeJoined()).thenReturn(false); when(member.hasTimeJoined()).thenReturn(false);
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(member)); CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(member));
Member loadedAuthor = Mockito.mock(Member.class); Member loadedAuthor = Mockito.mock(Member.class);
when(member.getGuild()).thenReturn(Mockito.mock(Guild.class));
when(botService.forceReloadMember(member)).thenReturn(CompletableFuture.completedFuture(loadedAuthor)); when(botService.forceReloadMember(member)).thenReturn(CompletableFuture.completedFuture(loadedAuthor));
when(self.sendResponse(eq(parameters), modelArgumentCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null)); when(self.sendResponse(eq(parameters), modelArgumentCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters); CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);

View File

@@ -65,6 +65,7 @@ public class MessageEmbedListenerTest {
public void setup(){ public void setup(){
when(guild.getIdLong()).thenReturn(ORIGIN_GUILD_ID); when(guild.getIdLong()).thenReturn(ORIGIN_GUILD_ID);
when(message.getGuild()).thenReturn(guild); when(message.getGuild()).thenReturn(guild);
when(message.getChannel()).thenReturn(textChannel);
} }
@Test @Test

View File

@@ -103,7 +103,6 @@ public class MessageEmbedRemovalReactionListenerTest {
AEmote reactedEmote = AEmote.builder().build(); AEmote reactedEmote = AEmote.builder().build();
when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote); when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote);
when(messageReaction.getReactionEmote()).thenReturn(reactionEmote); when(messageReaction.getReactionEmote()).thenReturn(reactionEmote);
when(botService.getEmote(serverId, reactedEmote)).thenReturn(Optional.of(emote));
when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(true); when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(true);
EmbeddedMessage message = EmbeddedMessage EmbeddedMessage message = EmbeddedMessage
.builder() .builder()
@@ -134,7 +133,6 @@ public class MessageEmbedRemovalReactionListenerTest {
AEmote reactedEmote = AEmote.builder().build(); AEmote reactedEmote = AEmote.builder().build();
when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote); when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote);
when(messageReaction.getReactionEmote()).thenReturn(reactionEmote); when(messageReaction.getReactionEmote()).thenReturn(reactionEmote);
when(botService.getEmote(serverId, reactedEmote)).thenReturn(Optional.of(emote));
when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(wasCorrectEmote); when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(wasCorrectEmote);
testUnit.executeReactionAdded(cachedMessage, messageReaction, userInAServer); testUnit.executeReactionAdded(cachedMessage, messageReaction, userInAServer);
verify(messageService, times(0)).deleteMessageInChannelInServer(serverId, channelId, messageId); verify(messageService, times(0)).deleteMessageInChannelInServer(serverId, channelId, messageId);

View File

@@ -3,6 +3,7 @@ package dev.sheldan.abstracto.utility.service;
import dev.sheldan.abstracto.core.models.AServerAChannelAUser; import dev.sheldan.abstracto.core.models.AServerAChannelAUser;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import dev.sheldan.abstracto.core.models.database.AUser;
import dev.sheldan.abstracto.core.models.database.AUserInAServer; import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import dev.sheldan.abstracto.core.service.BotService; import dev.sheldan.abstracto.core.service.BotService;
import dev.sheldan.abstracto.core.service.ChannelService; import dev.sheldan.abstracto.core.service.ChannelService;
@@ -145,7 +146,11 @@ public class RemindServiceBeanTest {
AServer server = MockUtils.getServer(); AServer server = MockUtils.getServer();
AChannel aChannel = MockUtils.getTextChannel(server, 4L); AChannel aChannel = MockUtils.getTextChannel(server, 4L);
Long reminderId = 5L; Long reminderId = 5L;
Reminder remindedReminder = Reminder.builder().reminded(false).server(server).channel(aChannel).id(reminderId).build(); AUserInAServer remindedUser = Mockito.mock(AUserInAServer.class);
AUser user = Mockito.mock(AUser.class);
when(user.getId()).thenReturn(6L);
when(remindedUser.getUserReference()).thenReturn(user);
Reminder remindedReminder = Reminder.builder().reminded(false).server(server).remindedUser(remindedUser).channel(aChannel).id(reminderId).build();
when(reminderManagementService.loadReminder(reminderId)).thenReturn(Optional.of(remindedReminder)); when(reminderManagementService.loadReminder(reminderId)).thenReturn(Optional.of(remindedReminder));
Guild guildMock = Mockito.mock(Guild.class); Guild guildMock = Mockito.mock(Guild.class);
when(botService.getGuildById(server.getId())).thenReturn(Optional.of(guildMock)); when(botService.getGuildById(server.getId())).thenReturn(Optional.of(guildMock));
@@ -157,8 +162,14 @@ public class RemindServiceBeanTest {
@Test @Test
public void testExecuteReminderFromNotFoundGuild() { public void testExecuteReminderFromNotFoundGuild() {
AServer server = MockUtils.getServer(); AServer server = MockUtils.getServer();
AChannel aChannel = Mockito.mock(AChannel.class);
when(aChannel.getId()).thenReturn(9L);
Long reminderId = 5L; Long reminderId = 5L;
Reminder remindedReminder = Reminder.builder().reminded(false).server(server).id(reminderId).build(); AUserInAServer remindedUser = Mockito.mock(AUserInAServer.class);
AUser user = Mockito.mock(AUser.class);
when(user.getId()).thenReturn(6L);
when(remindedUser.getUserReference()).thenReturn(user);
Reminder remindedReminder = Reminder.builder().reminded(false).server(server).channel(aChannel).remindedUser(remindedUser).id(reminderId).build();
when(reminderManagementService.loadReminder(reminderId)).thenReturn(Optional.of(remindedReminder)); when(reminderManagementService.loadReminder(reminderId)).thenReturn(Optional.of(remindedReminder));
when(botService.getGuildById(server.getId())).thenReturn(Optional.empty()); when(botService.getGuildById(server.getId())).thenReturn(Optional.empty());
testUnit.executeReminder(reminderId); testUnit.executeReminder(reminderId);

View File

@@ -131,7 +131,7 @@ public class StarboardServiceBeanTest {
when(configService.getLongValue("starLvl2", server.getId())).thenReturn(2L); when(configService.getLongValue("starLvl2", server.getId())).thenReturn(2L);
when(emoteService.getUsableEmoteOrDefault(server.getId(), "star2")).thenReturn("b"); when(emoteService.getUsableEmoteOrDefault(server.getId(), "star2")).thenReturn("b");
testUnit.createStarboardPost(message, userExceptAuthor, userReacting, starredUser); testUnit.createStarboardPost(message, userExceptAuthor, userReacting, starredUser);
verify(self, times(1)).persistPost(eq(message), anyList(), eq(futures), eq(channelId), eq(starredUser.getUserInServerId()), eq(userReacting.getUserInServerId())); verify(self, times(1)).persistPost(eq(message), anyList(), eq(futures), eq(channelId), eq(starredUser.getUserInServerId()));
List<StarboardPostModel> starboardPostModels = starboardPostModelArgumentCaptor.getAllValues(); List<StarboardPostModel> starboardPostModels = starboardPostModelArgumentCaptor.getAllValues();
Assert.assertEquals(1, starboardPostModels.size()); Assert.assertEquals(1, starboardPostModels.size());
StarboardPostModel usedModel = starboardPostModels.get(0); StarboardPostModel usedModel = starboardPostModels.get(0);
@@ -162,7 +162,7 @@ public class StarboardServiceBeanTest {
AUserInAServer secondStarrerUserObj = MockUtils.getUserObject(secondStarrerUserId, server); AUserInAServer secondStarrerUserObj = MockUtils.getUserObject(secondStarrerUserId, server);
when(userInServerManagementService.loadUserConditional(secondStarrerUserId)).thenReturn(Optional.of(secondStarrerUserObj)); when(userInServerManagementService.loadUserConditional(secondStarrerUserId)).thenReturn(Optional.of(secondStarrerUserObj));
when(userInServerManagementService.loadUserConditional(userReacting.getUserInServerId())).thenReturn(Optional.of(userReacting)); when(userInServerManagementService.loadUserConditional(userReacting.getUserInServerId())).thenReturn(Optional.of(userReacting));
testUnit.persistPost(message, userExceptAuthorIds, futures, channelId, starredUser.getUserInServerId(), userReacting.getUserInServerId()); testUnit.persistPost(message, userExceptAuthorIds, futures, channelId, starredUser.getUserInServerId());
verify(starboardPostReactorManagementService, times(2)).addReactor(eq(post), userInAServerArgumentCaptor.capture()); verify(starboardPostReactorManagementService, times(2)).addReactor(eq(post), userInAServerArgumentCaptor.capture());
List<AUserInAServer> addedReactors = userInAServerArgumentCaptor.getAllValues(); List<AUserInAServer> addedReactors = userInAServerArgumentCaptor.getAllValues();
Assert.assertEquals(secondStarrerUserId, addedReactors.get(0).getUserInServerId()); Assert.assertEquals(secondStarrerUserId, addedReactors.get(0).getUserInServerId());
@@ -178,6 +178,8 @@ public class StarboardServiceBeanTest {
Long oldPostId = 36L; Long oldPostId = 36L;
AUserInAServer starredUser = MockUtils.getUserObject(5L, server); AUserInAServer starredUser = MockUtils.getUserObject(5L, server);
Long channelId = 10L; Long channelId = 10L;
AChannel sourceChannel = Mockito.mock(AChannel.class);
when(sourceChannel.getServer()).thenReturn(server);
CachedMessage message = CachedMessage CachedMessage message = CachedMessage
.builder() .builder()
.authorId(starredUser.getUserReference().getId()) .authorId(starredUser.getUserReference().getId())
@@ -185,7 +187,7 @@ public class StarboardServiceBeanTest {
.channelId(channelId) .channelId(channelId)
.build(); .build();
Long starboardPostId = 47L; Long starboardPostId = 47L;
StarboardPost post = StarboardPost.builder().postMessageId(postMessageId).starboardMessageId(oldPostId).id(starboardPostId).build(); StarboardPost post = StarboardPost.builder().postMessageId(postMessageId).starboardMessageId(oldPostId).sourceChanel(sourceChannel).id(starboardPostId).build();
MessageToSend postMessage = MessageToSend.builder().build(); MessageToSend postMessage = MessageToSend.builder().build();
when(templateService.renderEmbedTemplate(eq(StarboardServiceBean.STARBOARD_POST_TEMPLATE), starboardPostModelArgumentCaptor.capture())).thenReturn(postMessage); when(templateService.renderEmbedTemplate(eq(StarboardServiceBean.STARBOARD_POST_TEMPLATE), starboardPostModelArgumentCaptor.capture())).thenReturn(postMessage);
when(postTargetService.editOrCreatedInPostTarget(oldPostId, postMessage, StarboardPostTarget.STARBOARD, server.getId())).thenReturn(Arrays.asList(CompletableFuture.completedFuture(sendPost))); when(postTargetService.editOrCreatedInPostTarget(oldPostId, postMessage, StarboardPostTarget.STARBOARD, server.getId())).thenReturn(Arrays.asList(CompletableFuture.completedFuture(sendPost)));
@@ -207,6 +209,7 @@ public class StarboardServiceBeanTest {
StarboardPost post = StarboardPost StarboardPost post = StarboardPost
.builder() .builder()
.starboardChannel(channel) .starboardChannel(channel)
.sourceChanel(channel)
.starboardMessageId(messageId) .starboardMessageId(messageId)
.build(); .build();
testUnit.deleteStarboardMessagePost(post); testUnit.deleteStarboardMessagePost(post);
@@ -275,6 +278,6 @@ public class StarboardServiceBeanTest {
Long secondStarrerUserId = 2L; Long secondStarrerUserId = 2L;
List<Long> userExceptAuthorIds = Arrays.asList(secondStarrerUserId, userReacting.getUserReference().getId()); List<Long> userExceptAuthorIds = Arrays.asList(secondStarrerUserId, userReacting.getUserReference().getId());
List<CompletableFuture<Message>> futures = Arrays.asList(CompletableFuture.completedFuture(sendPost)); List<CompletableFuture<Message>> futures = Arrays.asList(CompletableFuture.completedFuture(sendPost));
testUnit.persistPost(message, userExceptAuthorIds, futures, channelId, starredUser.getUserInServerId(), userReacting.getUserInServerId()); testUnit.persistPost(message, userExceptAuthorIds, futures, channelId, starredUser.getUserInServerId());
} }
} }

View File

@@ -97,6 +97,8 @@ public class SuggestionServiceBeanTest {
@Test @Test
public void testCreateSuggestion() { public void testCreateSuggestion() {
Member member = Mockito.mock(Member.class); Member member = Mockito.mock(Member.class);
when(member.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("5");
String text = "text"; String text = "text";
Message message = Mockito.mock(Message.class); Message message = Mockito.mock(Message.class);
Long suggestionId = 3L; Long suggestionId = 3L;
@@ -172,6 +174,8 @@ public class SuggestionServiceBeanTest {
MessageEmbed embed = Mockito.mock(MessageEmbed.class); MessageEmbed embed = Mockito.mock(MessageEmbed.class);
when(embed.getDescription()).thenReturn("description"); when(embed.getDescription()).thenReturn("description");
Message suggestionMessage = Mockito.mock(Message.class); Message suggestionMessage = Mockito.mock(Message.class);
when(suggestionMessage.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("8");
when(suggestionMessage.getEmbeds()).thenReturn(Arrays.asList(embed)); when(suggestionMessage.getEmbeds()).thenReturn(Arrays.asList(embed));
MessageToSend updatedMessage = MessageToSend.builder().build(); MessageToSend updatedMessage = MessageToSend.builder().build();
when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_LOG_TEMPLATE), any(SuggestionLog.class))).thenReturn(updatedMessage); when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_LOG_TEMPLATE), any(SuggestionLog.class))).thenReturn(updatedMessage);

View File

@@ -59,7 +59,7 @@ public class StarboardPostReactorManagementServiceBeanTest {
@Test @Test
public void testRemoveReactors() { public void testRemoveReactors() {
StarboardPost post = StarboardPost.builder().build(); StarboardPost post = StarboardPost.builder().reactions(new ArrayList<>()).build();
testUnit.removeReactors(post); testUnit.removeReactors(post);
verify(repository, times(1)).deleteByStarboardPost(post); verify(repository, times(1)).deleteByStarboardPost(post);
} }

View File

@@ -9,6 +9,7 @@ import dev.sheldan.abstracto.test.MockUtils;
import dev.sheldan.abstracto.utility.models.SuggestionState; import dev.sheldan.abstracto.utility.models.SuggestionState;
import dev.sheldan.abstracto.utility.models.database.Suggestion; import dev.sheldan.abstracto.utility.models.database.Suggestion;
import dev.sheldan.abstracto.utility.repository.SuggestionRepository; import dev.sheldan.abstracto.utility.repository.SuggestionRepository;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member; import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message; import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel; import net.dv8tion.jda.api.entities.MessageChannel;
@@ -48,12 +49,15 @@ public class SuggestionManagementServiceBeanTest {
AServer server = MockUtils.getServer(); AServer server = MockUtils.getServer();
AUserInAServer userInAServer = MockUtils.getUserObject(5L, server); AUserInAServer userInAServer = MockUtils.getUserObject(5L, server);
String text = "text"; String text = "text";
Guild guild = Mockito.mock(Guild.class);
Message message = Mockito.mock(Message.class); Message message = Mockito.mock(Message.class);
MessageChannel messageChannel = Mockito.mock(MessageChannel.class); MessageChannel messageChannel = Mockito.mock(MessageChannel.class);
when(messageChannel.getIdLong()).thenReturn(CHANNEL_ID); when(messageChannel.getIdLong()).thenReturn(CHANNEL_ID);
when(message.getChannel()).thenReturn(messageChannel); when(message.getChannel()).thenReturn(messageChannel);
when(message.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("8");
long suggestionId = 1L; long suggestionId = 1L;
Suggestion createdSuggestion = testUnit.createSuggestion(userInAServer, text,message, suggestionId); Suggestion createdSuggestion = testUnit.createSuggestion(userInAServer, text, message, suggestionId);
verify(suggestionRepository, times(1)).save(createdSuggestion); verify(suggestionRepository, times(1)).save(createdSuggestion);
Assert.assertEquals(SuggestionState.NEW, createdSuggestion.getState()); Assert.assertEquals(SuggestionState.NEW, createdSuggestion.getState());
Assert.assertEquals(userInAServer.getUserInServerId(), createdSuggestion.getSuggester().getUserInServerId()); Assert.assertEquals(userInAServer.getUserInServerId(), createdSuggestion.getSuggester().getUserInServerId());
@@ -66,10 +70,13 @@ public class SuggestionManagementServiceBeanTest {
AServer server = MockUtils.getServer(); AServer server = MockUtils.getServer();
AUserInAServer userInAServer = MockUtils.getUserObject(5L, server); AUserInAServer userInAServer = MockUtils.getUserObject(5L, server);
String text = "text"; String text = "text";
Guild guild = Mockito.mock(Guild.class);
Message message = Mockito.mock(Message.class); Message message = Mockito.mock(Message.class);
MessageChannel messageChannel = Mockito.mock(MessageChannel.class); MessageChannel messageChannel = Mockito.mock(MessageChannel.class);
when(messageChannel.getIdLong()).thenReturn(CHANNEL_ID); when(messageChannel.getIdLong()).thenReturn(CHANNEL_ID);
when(message.getChannel()).thenReturn(messageChannel); when(message.getChannel()).thenReturn(messageChannel);
when(message.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("5");
when(userInServerManagementService.loadUser(member)).thenReturn(userInAServer); when(userInServerManagementService.loadUser(member)).thenReturn(userInAServer);
long suggestionId = 1L; long suggestionId = 1L;
Suggestion createdSuggestion = testUnit.createSuggestion(member, text, message, suggestionId); Suggestion createdSuggestion = testUnit.createSuggestion(member, text, message, suggestionId);

View File

@@ -33,6 +33,8 @@ public class StarboardFeature implements FeatureConfig {
return Arrays.asList(starboardFeatureValidator); return Arrays.asList(starboardFeatureValidator);
} }
// TODO add missing system config keys
@Override @Override
public List<String> getRequiredEmotes() { public List<String> getRequiredEmotes() {
return Arrays.asList("star", "star1", "star2", "star3", "star4", "starboardBadge1", "starboardBadge2", "starboardBadge3"); return Arrays.asList("star", "star1", "star2", "star3", "star4", "starboardBadge1", "starboardBadge2", "starboardBadge3");

View File

@@ -11,6 +11,7 @@ import net.dv8tion.jda.api.entities.Member;
@Getter @Getter
@Setter @Setter
@SuperBuilder @SuperBuilder
// TODO change user initiated context so slim context, and remove database entities referenced
public class SuggestionLog extends UserInitiatedServerContext { public class SuggestionLog extends UserInitiatedServerContext {
private Long suggestionId; private Long suggestionId;
private SuggestionState state; private SuggestionState state;

View File

@@ -103,26 +103,29 @@ public class CommandReceivedHandler extends ListenerAdapter {
UnParsedCommandParameter unParsedParameter = new UnParsedCommandParameter(contentStripped); UnParsedCommandParameter unParsedParameter = new UnParsedCommandParameter(contentStripped);
String commandName = commandManager.getCommandName(parameters.get(0), event.getGuild().getIdLong()); String commandName = commandManager.getCommandName(parameters.get(0), event.getGuild().getIdLong());
foundCommand = commandManager.findCommandByParameters(commandName, unParsedParameter); foundCommand = commandManager.findCommandByParameters(commandName, unParsedParameter);
tryToExecuteFoundCommand(event, userInitiatedContext, commandContextBuilder, foundCommand, unParsedParameter); tryToExecuteFoundCommand(event, commandContextBuilder, foundCommand, unParsedParameter);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception when preparing command.", e); log.error("Exception when executing command.", e);
CommandResult commandResult = CommandResult.fromError(e.getMessage(), e); CommandResult commandResult = CommandResult.fromError(e.getMessage(), e);
CommandContext commandContext = commandContextBuilder.build(); CommandContext commandContext = commandContextBuilder.build();
self.executePostCommandListener(null, commandContext, commandResult); self.executePostCommandListener(null, commandContext, commandResult);
} }
} }
private void tryToExecuteFoundCommand(@Nonnull MessageReceivedEvent event, UserInitiatedServerContext userInitiatedContext, CommandContext.CommandContextBuilder commandContextBuilder, Command foundCommand, UnParsedCommandParameter unParsedParameter) { private void tryToExecuteFoundCommand(@Nonnull MessageReceivedEvent event, CommandContext.CommandContextBuilder commandContextBuilder, Command foundCommand, UnParsedCommandParameter unParsedParameter) {
try { try {
Parameters parsedParameters = getParsedParameters(unParsedParameter, foundCommand, event.getMessage(), userInitiatedContext); Parameters parsedParameters = getParsedParameters(unParsedParameter, foundCommand, event.getMessage());
validateCommandParameters(parsedParameters, foundCommand); validateCommandParameters(parsedParameters, foundCommand);
CommandContext commandContext = commandContextBuilder.parameters(parsedParameters).build(); CommandContext commandContext = commandContextBuilder.parameters(parsedParameters).build();
ConditionResult conditionResult = commandService.isCommandExecutable(foundCommand, commandContext); ConditionResult conditionResult = commandService.isCommandExecutable(foundCommand, commandContext);
CommandResult commandResult = null; CommandResult commandResult = null;
if(conditionResult.isResult()) { if(conditionResult.isResult()) {
if(foundCommand.getConfiguration().isAsync()) { if(foundCommand.getConfiguration().isAsync()) {
foundCommand.executeAsync(commandContext).thenAccept(result -> log.info("Executing async command {} for server {} in channel {} based on message {} by user {}.",
foundCommand.getConfiguration().getName(), commandContext.getGuild().getId(), commandContext.getChannel().getId(), commandContext.getMessage().getId(), commandContext.getAuthor().getId());
foundCommand.executeAsync(commandContext).thenAccept(result ->
executePostCommandListener(foundCommand, commandContext, result) executePostCommandListener(foundCommand, commandContext, result)
).exceptionally(throwable -> { ).exceptionally(throwable -> {
log.error("Asynchronous command {} failed.", foundCommand.getConfiguration().getName(), throwable); log.error("Asynchronous command {} failed.", foundCommand.getConfiguration().getName(), throwable);
@@ -169,6 +172,7 @@ public class CommandReceivedHandler extends ListenerAdapter {
for (ParameterValidator parameterValidator : parameter.getValidators()) { for (ParameterValidator parameterValidator : parameter.getValidators()) {
boolean validate = parameterValidator.validate(parameters.getParameters().get(i)); boolean validate = parameterValidator.validate(parameters.getParameters().get(i));
if(!validate) { if(!validate) {
log.trace("Parameter {} in command {} failed to validate.", parameter.getName(), foundCommand.getConfiguration().getName());
throw new CommandParameterValidationException(parameterValidator.getParameters(), parameterValidator.getTemplateName(), parameter); throw new CommandParameterValidationException(parameterValidator.getParameters(), parameterValidator.getTemplateName(), parameter);
} }
} }
@@ -177,6 +181,7 @@ public class CommandReceivedHandler extends ListenerAdapter {
@Transactional @Transactional
public void executePostCommandListener(Command foundCommand, CommandContext commandContext, CommandResult result) { public void executePostCommandListener(Command foundCommand, CommandContext commandContext, CommandResult result) {
log.trace("Executing post command listeners for command from message {}.", commandContext.getMessage().getIdLong());
for (PostCommandExecution postCommandExecution : executions) { for (PostCommandExecution postCommandExecution : executions) {
postCommandExecution.execute(commandContext, result, foundCommand); postCommandExecution.execute(commandContext, result, foundCommand);
} }
@@ -184,6 +189,8 @@ public class CommandReceivedHandler extends ListenerAdapter {
@Transactional @Transactional
public CommandResult executeCommand(Command foundCommand, CommandContext commandContext) { public CommandResult executeCommand(Command foundCommand, CommandContext commandContext) {
log.info("Executing sync command {} for server {} in channel {} based on message {} by user {}.",
foundCommand.getConfiguration().getName(), commandContext.getGuild().getId(), commandContext.getChannel().getId(), commandContext.getMessage().getId(), commandContext.getAuthor().getId());
return foundCommand.execute(commandContext); return foundCommand.execute(commandContext);
} }
@@ -203,11 +210,12 @@ public class CommandReceivedHandler extends ListenerAdapter {
.build(); .build();
} }
public Parameters getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message, UserInitiatedServerContext userInitiatedServerContext){ public Parameters getParsedParameters(UnParsedCommandParameter unParsedCommandParameter, Command command, Message message){
List<Object> parsedParameters = new ArrayList<>(); List<Object> parsedParameters = new ArrayList<>();
if(command.getConfiguration().getParameters() == null || command.getConfiguration().getParameters().isEmpty()) { if(command.getConfiguration().getParameters() == null || command.getConfiguration().getParameters().isEmpty()) {
return Parameters.builder().parameters(parsedParameters).build(); return Parameters.builder().parameters(parsedParameters).build();
} }
log.trace("Parsing parameters for command {} based on message {}.", command.getConfiguration().getName(), message.getId());
Iterator<TextChannel> channelIterator = message.getMentionedChannels().iterator(); Iterator<TextChannel> channelIterator = message.getMentionedChannels().iterator();
Iterator<Emote> emoteIterator = message.getEmotesBag().iterator(); Iterator<Emote> emoteIterator = message.getEmotesBag().iterator();
Iterator<Member> memberIterator = message.getMentionedMembers().iterator(); Iterator<Member> memberIterator = message.getMentionedMembers().iterator();

View File

@@ -6,12 +6,14 @@ import dev.sheldan.abstracto.core.command.service.management.CommandInServerMana
import dev.sheldan.abstracto.core.command.service.management.CommandManagementService; import dev.sheldan.abstracto.core.command.service.management.CommandManagementService;
import dev.sheldan.abstracto.core.listener.ServerConfigListener; import dev.sheldan.abstracto.core.listener.ServerConfigListener;
import dev.sheldan.abstracto.core.models.database.AServer; import dev.sheldan.abstracto.core.models.database.AServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
@Component @Component
@Slf4j
public class CommandConfigListener implements ServerConfigListener { public class CommandConfigListener implements ServerConfigListener {
@Autowired @Autowired
@@ -25,6 +27,7 @@ public class CommandConfigListener implements ServerConfigListener {
@Override @Override
public void updateServerConfig(AServer server) { public void updateServerConfig(AServer server) {
log.info("Creating command instances for server {}.", server.getId());
commandList.forEach(command -> { commandList.forEach(command -> {
if(command.getConfiguration() != null) { if(command.getConfiguration() != null) {
ACommand aCommand = commandManagementService.findCommandByName(command.getConfiguration().getName()); ACommand aCommand = commandManagementService.findCommandByName(command.getConfiguration().getName());

View File

@@ -5,14 +5,20 @@ import dev.sheldan.abstracto.core.command.execution.CommandContext;
import dev.sheldan.abstracto.core.command.execution.CommandResult; import dev.sheldan.abstracto.core.command.execution.CommandResult;
import dev.sheldan.abstracto.core.command.execution.ResultState; import dev.sheldan.abstracto.core.command.execution.ResultState;
import dev.sheldan.abstracto.core.command.service.PostCommandExecution; import dev.sheldan.abstracto.core.command.service.PostCommandExecution;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
@Slf4j
public class SelfDestructPostExecution implements PostCommandExecution { public class SelfDestructPostExecution implements PostCommandExecution {
@Override @Override
public void execute(CommandContext commandContext, CommandResult commandResult, Command command) { public void execute(CommandContext commandContext, CommandResult commandResult, Command command) {
if(commandResult.getResult().equals(ResultState.SELF_DESTRUCT)) { if(commandResult.getResult().equals(ResultState.SELF_DESTRUCT)) {
commandContext.getMessage().delete().queue(); Message message = commandContext.getMessage();
log.trace("Command {} is of type self destruct. Deleting message {} in channel {} in server {}.",
command.getConfiguration().getName(), message.getId(), message.getChannel().getId(), message.getGuild().getId());
message.delete().queue();
} }
} }
} }

View File

@@ -21,6 +21,7 @@ public class UndoActionPostExecution implements PostCommandExecution {
public void execute(CommandContext commandContext, CommandResult commandResult, Command command) { public void execute(CommandContext commandContext, CommandResult commandResult, Command command) {
ResultState result = commandResult.getResult(); ResultState result = commandResult.getResult();
if(result.equals(ResultState.ERROR) && commandContext.getUndoActions() != null && !commandContext.getUndoActions().isEmpty()) { if(result.equals(ResultState.ERROR) && commandContext.getUndoActions() != null && !commandContext.getUndoActions().isEmpty()) {
log.info("Performing undo cations for command {} in server {}.", command.getConfiguration().getName(), commandContext.getGuild().getIdLong());
undoActionService.performActionsFuture(commandContext.getUndoActions()).whenComplete((aVoid, undoThrowable) -> { undoActionService.performActionsFuture(commandContext.getUndoActions()).whenComplete((aVoid, undoThrowable) -> {
if(undoThrowable != null) { if(undoThrowable != null) {
log.warn("Undo actions failed.", undoThrowable); log.warn("Undo actions failed.", undoThrowable);

View File

@@ -8,11 +8,12 @@ import org.springframework.data.jpa.repository.QueryHints;
import javax.persistence.QueryHint; import javax.persistence.QueryHint;
import java.util.List; import java.util.List;
import java.util.Optional;
public interface ChannelGroupCommandRepository extends JpaRepository<AChannelGroupCommand, Long> { public interface ChannelGroupCommandRepository extends JpaRepository<AChannelGroupCommand, Long> {
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
AChannelGroupCommand findByCommandAndGroup(ACommand command, AChannelGroup group); Optional<AChannelGroupCommand> findByCommandAndGroup(ACommand command, AChannelGroup group);
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true")) @QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
List<AChannelGroupCommand> findByCommand(ACommand command); List<AChannelGroupCommand> findByCommand(ACommand command);

View File

@@ -4,6 +4,7 @@ import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.service.management.ChannelGroupCommandManagementService; import dev.sheldan.abstracto.core.command.service.management.ChannelGroupCommandManagementService;
import dev.sheldan.abstracto.core.models.database.AChannel; import dev.sheldan.abstracto.core.models.database.AChannel;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand; import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@@ -11,6 +12,7 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component @Component
@Slf4j
public class ChannelGroupCommandServiceBean implements ChannelGroupCommandService { public class ChannelGroupCommandServiceBean implements ChannelGroupCommandService {
@Autowired @Autowired
@@ -23,9 +25,12 @@ public class ChannelGroupCommandServiceBean implements ChannelGroupCommandServic
Optional<AChannel> channelInGroup = aChannelGroupCommand.getGroup() Optional<AChannel> channelInGroup = aChannelGroupCommand.getGroup()
.getChannels().stream().filter(channel1 -> channel1.getId().equals(channel.getId())).findAny(); .getChannels().stream().filter(channel1 -> channel1.getId().equals(channel.getId())).findAny();
if (channelInGroup.isPresent() && aChannelGroupCommand.getEnabled()) { if (channelInGroup.isPresent() && aChannelGroupCommand.getEnabled()) {
log.trace("Command {} is enabled because the channel is part of group {} in server.", command.getName(), aChannelGroupCommand.getGroup().getId());
return true; return true;
} }
} }
// empty -> no groups, command enabled
// not empty -> has groups, command is disabled in all
return allChannelGroupsOfCommand.isEmpty(); return allChannelGroupsOfCommand.isEmpty();
} }
} }

View File

@@ -73,14 +73,10 @@ public class CommandManager implements CommandRegistry {
} }
public Command findCommand(String name) { public Command findCommand(String name) {
Optional<Command> commandOptional = commands.stream().filter((Command o )-> { return commands.stream().filter((Command o )-> {
CommandConfiguration commandConfiguration = o.getConfiguration(); CommandConfiguration commandConfiguration = o.getConfiguration();
return commandConfiguration.getName().equals(name); return commandConfiguration.getName().equals(name);
}).findFirst(); }).findFirst().orElseThrow(CommandNotFoundException::new);
if(commandOptional.isPresent()){
return commandOptional.get();
}
throw new CommandNotFoundException();
} }
@Override @Override
@@ -102,7 +98,7 @@ public class CommandManager implements CommandRegistry {
@Override @Override
public boolean isCommand(Message message) { public boolean isCommand(Message message) {
return message.getContentRaw().startsWith(configService.getStringValue(PREFIX, message.getGuild().getIdLong(), defaultConfigManagementService.getDefaultConfig(PREFIX).getStringValue())); return message.getContentRaw().startsWith(configService.getStringValue(PREFIX, message.getGuild().getIdLong(), getDefaultPrefix()));
} }
@Override @Override
@@ -117,6 +113,10 @@ public class CommandManager implements CommandRegistry {
@Override @Override
public String getCommandName(String input, Long serverId) { public String getCommandName(String input, Long serverId) {
return input.replaceFirst(configService.getStringValue(PREFIX, serverId, defaultConfigManagementService.getDefaultConfig(PREFIX).getStringValue()), ""); return input.replaceFirst(configService.getStringValue(PREFIX, serverId, getDefaultPrefix()), "");
}
private String getDefaultPrefix() {
return defaultConfigManagementService.getDefaultConfig(PREFIX).getStringValue();
} }
} }

View File

@@ -66,6 +66,7 @@ public class CommandServiceBean implements CommandService {
if(commandForServer.getAllowedRoles().stream().noneMatch(role1 -> role1.getId().equals(role.getId()))) { if(commandForServer.getAllowedRoles().stream().noneMatch(role1 -> role1.getId().equals(role.getId()))) {
commandForServer.getAllowedRoles().add(role); commandForServer.getAllowedRoles().add(role);
} }
log.info("Allowing command {} for role {} in server {}.", aCommand.getName(), role.getId(), role.getServer().getId());
commandForServer.setRestricted(true); commandForServer.setRestricted(true);
} }
@@ -73,6 +74,7 @@ public class CommandServiceBean implements CommandService {
public void allowFeatureForRole(FeatureEnum featureEnum, ARole role) { public void allowFeatureForRole(FeatureEnum featureEnum, ARole role) {
AFeature feature = featureManagementService.getFeature(featureEnum.getKey()); AFeature feature = featureManagementService.getFeature(featureEnum.getKey());
feature.getCommands().forEach(command -> this.allowCommandForRole(command, role)); feature.getCommands().forEach(command -> this.allowCommandForRole(command, role));
log.info("Allowing feature {} for role {} in server {}.", feature.getKey(), role.getId(), role.getServer().getId());
} }
@Override @Override
@@ -81,18 +83,21 @@ public class CommandServiceBean implements CommandService {
if(commandForServer.getImmuneRoles().stream().noneMatch(role1 -> role1.getId().equals(role.getId()))) { if(commandForServer.getImmuneRoles().stream().noneMatch(role1 -> role1.getId().equals(role.getId()))) {
commandForServer.getImmuneRoles().add(role); commandForServer.getImmuneRoles().add(role);
} }
log.info("Making role {} immune from command {} in server {}.", role.getId(), aCommand.getName(), role.getServer().getId());
} }
@Override @Override
public void makeRoleAffectedByCommand(ACommand aCommand, ARole role) { public void makeRoleAffectedByCommand(ACommand aCommand, ARole role) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer()); ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer());
commandForServer.getImmuneRoles().removeIf(role1 -> role1.getId().equals(role.getId())); commandForServer.getImmuneRoles().removeIf(role1 -> role1.getId().equals(role.getId()));
log.info("Making role {} affected from command {} in server {}.", role.getId(), aCommand.getName(), role.getServer().getId());
} }
@Override @Override
public void restrictCommand(ACommand aCommand, AServer server) { public void restrictCommand(ACommand aCommand, AServer server) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, server); ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, server);
commandForServer.setRestricted(true); commandForServer.setRestricted(true);
log.info("Restricting command {} in server {}.", aCommand.getName(), server.getId());
} }
@Override @Override
@@ -119,6 +124,7 @@ public class CommandServiceBean implements CommandService {
public void unRestrictCommand(ACommand aCommand, AServer server) { public void unRestrictCommand(ACommand aCommand, AServer server) {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, server); ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, server);
commandForServer.setRestricted(false); commandForServer.setRestricted(false);
log.info("Removing restriction on command {} in server {}.", aCommand.getName(), server.getId());
} }
@Override @Override
@@ -126,12 +132,14 @@ public class CommandServiceBean implements CommandService {
ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer()); ACommandInAServer commandForServer = commandInServerManagementService.getCommandForServer(aCommand, role.getServer());
commandForServer.setRestricted(true); commandForServer.setRestricted(true);
commandForServer.getAllowedRoles().removeIf(role1 -> role1.getId().equals(role.getId())); commandForServer.getAllowedRoles().removeIf(role1 -> role1.getId().equals(role.getId()));
log.info("Disallowing command {} for role {} in server {}.", aCommand.getName(), role.getId(), role.getServer().getId());
} }
@Override @Override
public void disAllowFeatureForRole(FeatureEnum featureEnum, ARole role) { public void disAllowFeatureForRole(FeatureEnum featureEnum, ARole role) {
AFeature feature = featureManagementService.getFeature(featureEnum.getKey()); AFeature feature = featureManagementService.getFeature(featureEnum.getKey());
feature.getCommands().forEach(command -> this.disAllowCommandForRole(command, role)); feature.getCommands().forEach(command -> this.disAllowCommandForRole(command, role));
log.info("Disallowing feature {} for role {} in server {}.", feature.getKey(), role.getId(), role.getServer().getId());
} }
public ConditionResult isCommandExecutable(Command command, CommandContext commandContext) { public ConditionResult isCommandExecutable(Command command, CommandContext commandContext) {

View File

@@ -44,9 +44,11 @@ public class ExceptionServiceBean implements ExceptionService {
if(command != null && command.getConfiguration().isSupportsEmbedException()) { if(command != null && command.getConfiguration().isSupportsEmbedException()) {
try { try {
GenericExceptionModel exceptionModel = buildCommandModel(throwable, context); GenericExceptionModel exceptionModel = buildCommandModel(throwable, context);
log.info("Reporting generic exception {} of command {} towards channel {} in server {}.",
throwable.getClass().getSimpleName(), command.getConfiguration().getName(), context.getChannel().getId(), context.getGuild().getId());
channelService.sendEmbedTemplateInChannel("generic_command_exception", exceptionModel, context.getChannel()); channelService.sendEmbedTemplateInChannel("generic_command_exception", exceptionModel, context.getChannel());
} catch (Exception e) { } catch (Exception e) {
log.error("Failed to notify about assignable role exception.", e); log.error("Failed to notify about exception.", e);
} }
} else if(throwable instanceof Templatable){ } else if(throwable instanceof Templatable){
GenericExceptionModel exceptionModel = buildCommandModel(throwable, context); GenericExceptionModel exceptionModel = buildCommandModel(throwable, context);

View File

@@ -2,14 +2,18 @@ package dev.sheldan.abstracto.core.command.service.management;
import dev.sheldan.abstracto.core.command.models.database.ACommand; import dev.sheldan.abstracto.core.command.models.database.ACommand;
import dev.sheldan.abstracto.core.command.repository.ChannelGroupCommandRepository; import dev.sheldan.abstracto.core.command.repository.ChannelGroupCommandRepository;
import dev.sheldan.abstracto.core.exception.AbstractoRunTimeException;
import dev.sheldan.abstracto.core.models.database.AChannelGroup; import dev.sheldan.abstracto.core.models.database.AChannelGroup;
import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand; import dev.sheldan.abstracto.core.models.database.AChannelGroupCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.Optional;
@Component @Component
@Slf4j
public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCommandManagementService { public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCommandManagementService {
@Autowired @Autowired
@@ -17,16 +21,16 @@ public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCom
@Override @Override
public void setCommandInGroupTo(ACommand command, AChannelGroup group, Boolean enabled) { public void setCommandInGroupTo(ACommand command, AChannelGroup group, Boolean enabled) {
AChannelGroupCommand groupCommand = groupCommandRepository.findByCommandAndGroup(command, group); Optional<AChannelGroupCommand> groupCommandOptional = groupCommandRepository.findByCommandAndGroup(command, group);
if(groupCommand == null) { AChannelGroupCommand groupCommand = groupCommandOptional.orElseGet(() -> createCommandInGroup(command, group));
groupCommand = createCommandInGroupTo(command, group);
}
groupCommand.setEnabled(enabled); groupCommand.setEnabled(enabled);
log.trace("Setting command {} enabled in group {} to {}.", command.getName(), group.getId(), enabled);
groupCommandRepository.save(groupCommand); groupCommandRepository.save(groupCommand);
} }
@Override @Override
public AChannelGroupCommand createCommandInGroupTo(ACommand command, AChannelGroup group) { public AChannelGroupCommand createCommandInGroup(ACommand command, AChannelGroup group) {
AChannelGroupCommand channelGroupCommand = AChannelGroupCommand AChannelGroupCommand channelGroupCommand = AChannelGroupCommand
.builder() .builder()
.command(command) .command(command)
@@ -34,13 +38,15 @@ public class ChannelGroupCommandManagementServiceBean implements ChannelGroupCom
.enabled(false) .enabled(false)
.build(); .build();
log.info("Creating command {} in group {}.", command.getName(), group.getId());
groupCommandRepository.save(channelGroupCommand); groupCommandRepository.save(channelGroupCommand);
return channelGroupCommand; return channelGroupCommand;
} }
@Override @Override
public AChannelGroupCommand getChannelGroupCommand(ACommand command, AChannelGroup group) { public AChannelGroupCommand getChannelGroupCommand(ACommand command, AChannelGroup group) {
return groupCommandRepository.findByCommandAndGroup(command, group); return groupCommandRepository.findByCommandAndGroup(command, group).orElseThrow(() -> new AbstractoRunTimeException("Command not found in group."));
} }
@Override @Override

Some files were not shown because too many files have changed in this diff Show More