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

View File

@@ -71,6 +71,7 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
}
MessageReaction.ReactionEmote reactionEmote = event.getReactionEmote();
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);
} else {
reaction.removeReaction(event.getUser()).submit();
@@ -84,13 +85,16 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
AssignableRolePlace assignableRolePlace = assignablePlacePost.getAssignablePlace();
List<CompletableFuture<Void>> futures = new ArrayList<>();
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(assignableRolePlace.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles configured. Removing existing reactions and roles.", assignableRolePlace.getId());
Optional<AssignedRoleUser> byUserInServer = assignedRoleUserManagementService.findByUserInServerOptional(userAdding);
byUserInServer.ifPresent(user -> futures.add(assignableRolePlaceService.removeExistingReactionsAndRoles(assignableRolePlace, user)));
}
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());
futures.add(CompletableFuture.allOf(roleAdditionFuture));
@@ -99,6 +103,7 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
}
}
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());
}
Long assignableRolePlaceId = assignableRolePlace.getId();
@@ -112,9 +117,11 @@ public class AssignablePostReactionAdded implements ReactedAddedListener {
AssignableRolePlace place = assignableRolePlaceManagementService.findByPlaceId(assignableRolePlaceId);
AUserInAServer userInAServer = userInServerManagementService.loadUser(userAdding);
if(place.getUniqueRoles()) {
log.trace("Assignable role place {} has unique roles. Deleting all existing references.", assignableRolePlaceId);
assignableRoleServiceBean.clearAllRolesOfUserInPlace(place, userInAServer);
}
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);
}

View File

@@ -49,6 +49,8 @@ public class AssignablePostReactionRemoved implements ReactedRemovedListener {
assignablePlacePost.getAssignableRoles().forEach(assignableRole -> {
if(emoteService.isReactionEmoteAEmote(reactionEmote, assignableRole.getEmote())) {
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 -> {
log.error("Failed to remove assignable role {} from user {}.", assignableRoleId, event.getMember(), throwable);
return null;

View File

@@ -109,7 +109,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
}
@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)) {
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();
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();
if(emoteOptional.isPresent()) {
AssignableRole toChange = emoteOptional.get();
toChange.setPosition(position);
} else {
throw new EmoteNotInAssignableRolePlaceException(emote, placeName);
}
throw new EmoteNotInAssignableRolePlaceException(emote, placeName);
}
@Override
@@ -145,6 +148,8 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
boolean emoteUsable = true;
if(fakeEmote.getEmote() != null) {
// 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();
}
if(emoteUsable) {
@@ -152,13 +157,17 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId));
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);
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
.builder()
.description(description)
.emote(fakeEmote)
.forceNewMessage(latestPost.getAssignableRoles().size() >= 20)
.forceNewMessage(forceNewMessage)
.build();
model.getRoles().add(newAssignableRole);
MessageToSend messageToSend = templateService.renderEmbedTemplate(ASSIGNABLE_ROLES_POST_TEMPLATE_KEY, model);
@@ -167,15 +176,19 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
if(channelOptional.isPresent()) {
TextChannel textChannel = channelOptional.get();
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 {
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 {
throw new ChannelNotFoundException(latestPost.getUsedChannel().getId());
}
} 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);
}
} else {
@@ -184,41 +197,50 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
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
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()
.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 -> {
self.addAssignableRoleInstanceWithPost(message.getIdLong(), placeId, roleId, description, fakeEmote, serverId);
return CompletableFuture.completedFuture(null);
log.trace("Adding reaction to message {} in server {} for assignable role place {}.", message.getId(), serverId, placeId);
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
public void addNewlyCreatedAssignablePlacePost(String placeName, String description,Long roleId, Long serverId, TextChannel textChannel, Message message, FullEmote fakeEmote) {
AChannel loadedChannel = channelManagementService.loadChannel(textChannel.getIdLong());
AServer loadedServer = serverManagementService.loadOrCreate(serverId);
public void addNewlyCreatedAssignablePlacePost(Long placeId, String description,Long roleId, Long serverId, Message message, FullEmote fakeEmote) {
log.info("Storing newly created assignable role place post {} for place {} in server {}.", message.getId(), placeId, serverId);
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);
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
.builder()
.id(message.getIdLong())
.usedChannel(loadedChannel)
.usedChannel(loadedPlace.getChannel())
.assignablePlace(loadedPlace)
.build();
@@ -228,25 +250,32 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
@Transactional
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);
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);
}
@Transactional
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);
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);
}
@Override
public CompletableFuture<Void> removeRoleFromAssignableRolePlace(AServer server, String placeName, FullEmote emote) {
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName);
Long assignableRolePlaceId = assignableRolePlace.getId();
for (AssignableRole assignableRole : assignableRolePlace.getAssignableRoles()) {
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 ->
self.deleteAssignableRoleFromPlace(server.getId(), placeName, assignableRole.getId())
self.deleteAssignableRoleFromPlace(assignableRolePlaceId, assignableRole.getId())
);
}
}
@@ -254,9 +283,9 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
}
@Transactional
public void deleteAssignableRoleFromPlace(Long serverId, String placeName, Long assignableRoleId) {
AServer server = serverManagementService.loadOrCreate(serverId);
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, placeName);
public void deleteAssignableRoleFromPlace(Long placeId, Long assignableRoleId) {
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByPlaceId(placeId);
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();
roleToRemoveOptional.ifPresent(assignableRole -> {
assignableRolePlace.getAssignableRoles().remove(assignableRole);
@@ -272,11 +301,13 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
List<AssignableRole> assignableRoles = assignableRolePlace.getAssignableRoles();
assignableRoles.sort(Comparator.comparing(AssignableRole::getPosition));
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));
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());
return CompletableFuture.allOf(fieldEditing, reactionRemoval);
} 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());
return CompletableFuture.completedFuture(null);
}
@@ -285,14 +316,16 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
@Override
public CompletableFuture<Void> setupAssignableRolePlace(AServer server, String 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);
assignableRolePlace.getMessagePosts().clear();
assignableRolePlace.getAssignableRoles().forEach(assignableRole ->
assignableRole.setAssignableRolePlacePost(null)
);
Long serverId = server.getId();
Long assignablePlaceId = assignableRolePlace.getId();
return CompletableFuture.allOf(oldPostDeletionFutures.toArray(new CompletableFuture[0]))
.thenCompose(aVoid -> self.createAssignableRolePlacePosts(serverId, name));
.thenCompose(aVoid -> self.createAssignableRolePlacePosts(serverId, assignablePlaceId));
}
@Override
@@ -303,6 +336,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
@Override
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);
List<AssignableRolePlacePost> existingMessagePosts = place.getMessagePosts();
existingMessagePosts.sort(Comparator.comparingLong(AssignableRolePlacePost::getId));
@@ -313,6 +347,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
TextChannel textChannel = channelOptional.get();
Iterator<MessageEmbed> iterator = messageToSend.getEmbeds().iterator();
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());
futures.add(messageCompletableFuture);
});
@@ -326,12 +361,14 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
List<AssignableRolePlacePost> existingMessagePosts = place.getMessagePosts();
if(!existingMessagePosts.isEmpty()) {
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));
AssignableRolePlacePost latestPost = existingMessagePosts.get(0);
Long channelId = latestPost.getUsedChannel().getId();
AssignableRolePlacePost firstPost = existingMessagePosts.get(0);
Long channelId = firstPost.getUsedChannel().getId();
Optional<TextChannel> channelOptional = channelService.getTextChannelInGuild(place.getServer().getId(), channelId);
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);
}
@@ -350,9 +387,11 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
private List<CompletableFuture<Void>> deleteExistingMessagePostsForPlace(AssignableRolePlace assignableRolePlace) {
List<CompletableFuture<Void>> oldPostDeletionFutures = new ArrayList<>();
assignableRolePlace.getMessagePosts().forEach(assignableRolePlacePost ->
oldPostDeletionFutures.add(messageService.deleteMessageInChannelInServer(assignableRolePlace.getServer().getId(), assignableRolePlacePost.getUsedChannel().getId(), assignableRolePlacePost.getId()))
);
assignableRolePlace.getMessagePosts().forEach(assignableRolePlacePost -> {
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;
}
@@ -484,6 +523,8 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
if(firstEmoteOptional.isPresent() && secondEmoteOptional.isPresent()) {
AssignableRole firstRole = firstEmoteOptional.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();
firstRole.setPosition(secondRole.getPosition());
secondRole.setPosition(firstPosition);
@@ -500,6 +541,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
public CompletableFuture<Void> testAssignableRolePlace(AServer server, String name, MessageChannel channel) {
AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name);
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);
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0]));
}
@@ -509,6 +551,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name);
List<AssignablePostConfigRole> roles = new ArrayList<>();
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());
for (AssignableRole role : assignableRoles) {
AEmote emoteForRole = role.getEmote();
@@ -521,6 +564,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
.position(role.getPosition())
.awardedRole(jdaRole)
.build();
log.trace("Displaying config for role {} with emote {} in position {}.", role.getId(), emoteForRole.getId(), role.getPosition());
roles.add(postRole);
}
AssignableRolePlaceConfig configModel = AssignableRolePlaceConfig
@@ -554,6 +598,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
@Override
public CompletableFuture<Void> changeText(AServer server, String name, String newText) {
AssignableRolePlace place = rolePlaceManagementService.findByServerAndKey(server, name);
log.info("Changing text of assignable role place {} in server {}.", place.getId(), server.getId());
place.setText(newText);
return refreshTextFromPlace(place);
}
@@ -562,10 +607,13 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
public CompletableFuture<Void> removeExistingReactionsAndRoles(AssignableRolePlace place, AssignedRoleUser user) {
Member memberInServer = botService.getMemberInServer(user.getUser());
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 -> {
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());
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(),
assignablePlacePost.getUsedChannel().getId(), assignablePlacePost.getId(), memberInServer));
});
@@ -599,6 +647,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
public CompletableFuture<Void> showAllAssignableRolePlaces(AServer server, MessageChannel channel) {
List<AssignableRolePlace> assignableRolePlaces = rolePlaceManagementService.findAllByServer(server);
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);
return CompletableFuture.allOf(promises.toArray(new CompletableFuture[0]));
}
@@ -608,6 +657,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
}
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 ->
emoteManagementService.deleteEmote(role.getEmote())
);
@@ -652,6 +702,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
current = rolesToAddIterator.next();
}
} else if(startOfNewMessage && lastAddedRole != null) {
log.trace("Forcing new message for post of assignable role place {}.", place.getId());
lastAddedRole.setForceNewMessage(true);
}
}
@@ -665,29 +716,30 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
}
@Transactional
public CompletableFuture<Void> createAssignableRolePlacePosts(Long serverId, String name) {
AServer server = serverManagementService.loadOrCreate(serverId);
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByServerAndKey(server, name);
public CompletableFuture<Void> createAssignableRolePlacePosts(Long serverId, Long assignablePlaceId) {
AssignableRolePlace assignableRolePlace = rolePlaceManagementService.findByPlaceId(assignablePlaceId);
Optional<TextChannel> channelOptional = botService.getTextChannelFromServerOptional(serverId, assignableRolePlace.getChannel().getId());
if(channelOptional.isPresent()) {
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);
return CompletableFuture.allOf(messageFutures.toArray(new CompletableFuture[0]))
.thenCompose(aVoid -> self.addEmotes(messageFutures, name));
.thenCompose(aVoid -> self.addEmotes(messageFutures, assignablePlaceId));
} else {
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
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();
Long serverId = firstMessage.getGuild().getIdLong();
AServer innerServer = serverManagementService.loadOrCreate(serverId);
AssignableRolePlace innerRolePlace = rolePlaceManagementService.findByServerAndKey(innerServer, placeKey);
AssignableRolePlace innerRolePlace = rolePlaceManagementService.findByPlaceId(assignablePlaceId);
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<CompletableFuture<Void>> reactionFutures = new ArrayList<>();
@@ -698,20 +750,21 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
MessageEmbed embed = sentMessage.getEmbeds().get(0);
List<AssignableRole> firstRoles = roleStream.subList(usedEmotes, 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());
CompletableFuture<Void> firstMessageFuture = createAssignableRolePlacePost(sentMessage, serverId, usedEmoteIds);
CompletableFuture<Void> firstMessageFuture = addingReactionsToAssignableRolePlacePost(sentMessage, serverId, usedEmoteIds);
reactionFutures.add(firstMessageFuture);
}
return CompletableFuture.allOf(reactionFutures.toArray(new CompletableFuture[0])).thenCompose(aVoid -> {
self.storeCreatedAssignableRolePlacePosts(placeKey, serverId, assignablePlacePostsMessageFutures);
self.storeCreatedAssignableRolePlacePosts(assignablePlaceId, serverId, assignablePlacePostsMessageFutures);
return CompletableFuture.completedFuture(null);
});
}
@Transactional
public void storeCreatedAssignableRolePlacePosts(String name, Long serverId, List<CompletableFuture<Message>> futures) {
AServer server = serverManagementService.loadOrCreate(serverId);
AssignableRolePlace updatedPlace = rolePlaceManagementService.findByServerAndKey(server, name);
public void storeCreatedAssignableRolePlacePosts(Long assignablePlaceId, Long serverId, List<CompletableFuture<Message>> futures) {
AssignableRolePlace updatedPlace = rolePlaceManagementService.findByPlaceId(assignablePlaceId);
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());
int usedEmotes = 0;
for (int i = 0; i < futures.size(); i++) {
@@ -721,6 +774,7 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
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
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());
usedEmotes += embed.getFields().size();
AssignableRolePlacePost post = AssignableRolePlacePost
@@ -740,9 +794,10 @@ public class AssignableRolePlaceServiceBean implements AssignableRolePlaceServic
}
@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
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 -> {
AEmote emoteToUseObject = emoteManagementService.loadEmote(emotesToUse);
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.service.RoleService;
import dev.sheldan.abstracto.core.service.management.UserInServerManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -17,6 +18,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class AssignableRoleServiceBean implements AssignableRoleService {
@Autowired
@@ -40,12 +42,15 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
@Override
public CompletableFuture<Void> assignAssignableRoleToUser(Long assignableRoleId, Member toAdd) {
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());
}
@Override
public void clearAllRolesOfUserInPlace(AssignableRolePlace place, AUserInAServer 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 -> {
if(assignableRole.getAssignablePlace().equals(place)) {
assignableRole.getAssignedUsers().remove(user);
@@ -63,6 +68,7 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
@Override
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());
}
@@ -82,11 +88,15 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
@Override
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);
}
@Override
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);
}
@@ -94,7 +104,7 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
public void addRoleToUser(Long assignableRoleId, Member member) {
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
AUserInAServer aUserInAServer = userInServerManagementService.loadUser(member);
assignedRoleUserManagementServiceBean.addAssignedRoleToUser(role, aUserInAServer);
addRoleToUser(role, aUserInAServer);
}
@Transactional
@@ -107,6 +117,6 @@ public class AssignableRoleServiceBean implements AssignableRoleService {
public void removeRoleFromUser(Long assignableRoleId, Member member) {
AssignableRole role = assignableRoleManagementServiceBean.getByAssignableRoleId(assignableRoleId);
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.management.EmoteManagementService;
import dev.sheldan.abstracto.core.service.management.RoleManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.MessageReaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class AssignableRoleManagementServiceBean implements AssignableRoleManagementService {
@Autowired
@@ -53,6 +55,7 @@ public class AssignableRoleManagementServiceBean implements AssignableRoleManage
.assignableRolePlacePost(post)
.build();
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;
}

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

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.repository.AssignedRoleUserRepository;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
@Slf4j
public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserManagementService {
@Autowired
@@ -19,6 +21,9 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Override
public void addAssignedRoleToUser(AssignableRole assignableRole, AUserInAServer 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));
assignableRole.getAssignedUsers().add(user);
user.getRoles().add(assignableRole);
@@ -26,6 +31,9 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Override
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);
assignableRole.getAssignedUsers().remove(user);
user.getRoles().remove(assignableRole);
@@ -33,6 +41,7 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Override
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();
return repository.save(newUser);
}
@@ -40,6 +49,7 @@ public class AssignedRoleUserManagementServiceBean implements AssignedRoleUserMa
@Override
public void clearAllAssignedRolesOfUser(AUserInAServer 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 ->
assignableRole.getAssignedUsers().remove(user)
);

View File

@@ -18,7 +18,7 @@ public interface AssignableRolePlaceService {
boolean hasAssignableRolePlaceEmote(AServer server, String placeName, AEmote emote);
boolean hasAssignableRolePlaceEmote(AssignableRolePlace place, AEmote emote);
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> removeRoleFromAssignableRolePlace(AServer server, String placeName, FullEmote emote);
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);
LeaderBoardModel leaderBoardModel = (LeaderBoardModel) ContextConverter.fromCommandContext(commandContext, LeaderBoardModel.class);
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());
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.templating.model.MessageToSend;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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
*/
@Component
@Slf4j
public class Rank extends AbstractConditionableCommand {
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());
rankModel.setRankUser(converter.fromLeaderBoardEntry(userRank));
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()));
MessageToSend messageToSend = templateService.renderEmbedTemplate(RANK_POST_EMBED_TEMPLATE, rankModel);
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.LeaderBoardEntry;
import dev.sheldan.abstracto.experience.models.templates.LeaderBoardEntryModel;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
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}
*/
@Component
@Slf4j
public class LeaderBoardModelConverter {
@Autowired
@@ -30,6 +32,7 @@ public class LeaderBoardModelConverter {
*/
public List<LeaderBoardEntryModel> fromLeaderBoard(LeaderBoard leaderBoard) {
List<LeaderBoardEntryModel> models = new ArrayList<>();
log.trace("Converting {} entries to a list of leaderbord entries.", leaderBoard.getEntries().size());
leaderBoard.getEntries().forEach(leaderBoardEntry -> {
LeaderBoardEntryModel entry = fromLeaderBoardEntry(leaderBoardEntry);
models.add(entry);

View File

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

View File

@@ -34,8 +34,10 @@ public class JoiningUserRoleListener implements JoinListener {
if(userExperience != null) {
log.info("User {} joined {} with previous experience. Setting up experience role again (if necessary).", member.getUser().getIdLong(), guild.getIdLong());
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.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -89,23 +88,27 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
*/
@Override
public void addExperience(AUserInAServer userInAServer) {
Long second = Instant.now().getEpochSecond() / 60;
Long minute = Instant.now().getEpochSecond() / 60;
Map<Long, List<ServerExperience>> runtimeExperience = runTimeExperienceService.getRuntimeExperience();
if(runtimeExperience.containsKey(second)) {
List<ServerExperience> existing = runtimeExperience.get(second);
existing.forEach(server -> {
if(server.getUserInServerIds().stream().noneMatch(userInAServer1 -> userInAServer.getUserInServerId().equals(userInAServer1))) {
if(runtimeExperience.containsKey(minute)) {
log.trace("Minute {} already tracked, adding user {} in server {}.",
minute, userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
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());
break;
}
});
}
} 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
.builder()
.serverId(userInAServer.getServerReference().getId())
.build();
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);
for (AExperienceLevel level : levels) {
if(level.getExperienceNeeded() >= experienceCount) {
log.trace("Calculated level {} for {} experience.", lastLevel.getLevel(), experienceCount);
return lastLevel;
} else {
lastLevel = level;
}
}
log.trace("Calculated level {} for {} experience.", lastLevel.getLevel(), experienceCount);
return lastLevel;
}
@@ -166,7 +171,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
// TODO what if there are a lot in here...., transaction size etc
servers.forEach(serverExp -> {
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 maxExp = configService.getLongValue(ExperienceFeatureConfig.MAX_EXP_KEY, serverExp.getServerId()).intValue();
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.");
}
} 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();
AExperienceLevel newLevel = calculateLevel(levels, newExperience);
Long newMessageCount = 1L;
@@ -246,6 +251,8 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}
AExperienceRole role = experienceRoleService.calculateRole(roles, currentLevel);
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
.builder()
.userInServerId(aUserInAServer.getUserInServerId())
@@ -254,6 +261,8 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}
Long experienceRoleId = role.getId();
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
.builder()
.experienceRoleId(experienceRoleId)
@@ -264,6 +273,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
@Transactional
public void persistExperienceChanges(List<ExperienceGainResult> resultFutures) {
List<AExperienceLevel> levels = experienceLevelManagementService.getLevelConfig();
log.info("Storing {} experience gain results.", resultFutures.size());
HashMap<Long, List<AExperienceRole>> serverRoleMapping = new HashMap<>();
resultFutures.forEach(experienceGainResult -> {
AUserInAServer user = userInServerManagementService.loadUser(experienceGainResult.getUserInServerId());
@@ -280,14 +290,14 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
if(foundLevel.isPresent()) {
userExperience.setCurrentLevel(foundLevel.get());
} 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();
if(!serverRoleMapping.containsKey(server.getId())) {
serverRoleMapping.put(server.getId(), experienceRoleManagementService.getExperienceRolesForServer(server));
}
List<AExperienceRole> roleConfig = serverRoleMapping.get(server.getId());
AExperienceRole role = experienceRoleService.calculateRole(roleConfig, userExperience.getLevelOrDefault());
RoleCalculationResult roleCalculationResult = experienceGainResult.getCalculationResult().join();
AExperienceRole role = experienceRoleManagementService.getExperienceRoleById(roleCalculationResult.getExperienceRoleId());
userExperience.setCurrentExperienceRole(role);
if(experienceGainResult.isCreateUserExperience()) {
userExperienceManagementService.saveUser(userExperience);
@@ -321,6 +331,8 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
Member member = botService.getMemberInServer(user.getServerReference(), user.getUserReference());
boolean currentlyHasNoExperienceRole = userExperience.getCurrentExperienceRole() == 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){
return roleService.removeRoleFromUserFuture(user, userExperience.getCurrentExperienceRole().getRole())
.thenApply(returnNullRole);
@@ -335,7 +347,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
.userInServerId(userInServerId)
.build();
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;
if(!currentlyHasNoExperienceRole && botService.isUserInGuild(userExperience.getUser())) {
removalFuture = roleService.removeRoleFromUserFuture(user, userExperience.getCurrentExperienceRole().getRole());
@@ -395,9 +407,11 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
AUserExperience userExperience = userExperienceManagementService.findUserInServer(user);
log.trace("Updating experience role for {} in server {} to {}", user.getUserInServerId(), user.getServerReference(), result.getExperienceRoleId());
if(result.getExperienceRoleId() != null) {
log.trace("User experience {} gets new experience role with id {}.", userExperience.getId(), result.getExperienceRoleId());
AExperienceRole role = experienceRoleManagementService.getExperienceRoleById(result.getExperienceRoleId());
userExperience.setCurrentExperienceRole(role);
} else {
log.trace("User experience {} does not get a user experience role.", userExperience.getId());
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) {
List<CompletableFuture<RoleCalculationResult>> futures = new ArrayList<>();
MessageToSend status = getUserSyncStatusUpdateModel(0, experiences.size());
try {
Message statusMessage = messageService.createStatusMessage(status, channel).get();
int interval = Math.min(Math.max(experiences.size() / 10, 1), 100);
for (int i = 0; i < experiences.size(); i++) {
if((i % interval) == 1) {
log.trace("Updating feedback message with new index {} out of {}", i, experiences.size());
status = getUserSyncStatusUpdateModel(i, experiences.size());
messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status);
}
futures.add(toExecute.apply(experiences.get(i)));
log.trace("Synchronizing {} out of {}", i, experiences.size());
Message statusMessage = messageService.createStatusMessage(status, channel).join();
int interval = Math.min(Math.max(experiences.size() / 10, 1), 100);
for (int i = 0; i < experiences.size(); i++) {
if((i % interval) == 1) {
log.trace("Updating feedback message with new index {} out of {}", i, experiences.size());
status = getUserSyncStatusUpdateModel(i, experiences.size());
messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status);
}
status = getUserSyncStatusUpdateModel(experiences.size(), experiences.size());
messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status);
} catch (InterruptedException | ExecutionException e) {
log.info("Failed to synchronize users.", e);
Thread.currentThread().interrupt();
futures.add(toExecute.apply(experiences.get(i)));
log.trace("Synchronizing {} out of {}", i, experiences.size());
}
status = getUserSyncStatusUpdateModel(experiences.size(), experiences.size());
messageService.updateStatusMessage(channel, statusMessage.getIdLong(), status);
return new CompletableFutureList<>(futures);
}
@Override
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);
userExperience.setExperienceGainDisabled(true);
}
@@ -445,6 +455,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
@Override
public void enableExperienceForUser(AUserInAServer userInAServer) {
AUserExperience userExperience = userExperienceManagementService.findUserInServer(userInAServer);
log.info("Enabling experience gain for user {} in server {}.", userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
userExperience.setExperienceGainDisabled(false);
}
@@ -478,8 +489,10 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
}
page--;
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<LeaderBoardEntry> entries = new ArrayList<>();
log.trace("Found {} experiences.", experiences.size());
for (int i = 0; i < experiences.size(); i++) {
AUserExperience userExperience = experiences.get(i);
entries.add(LeaderBoardEntry.builder().experience(userExperience).rank((page * pageSize) + i + 1).build());
@@ -494,7 +507,7 @@ public class AUserExperienceServiceBean implements AUserExperienceService {
*/
@Override
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);
Integer rank = 0;
if(aUserExperience != null) {

View File

@@ -21,7 +21,7 @@ public class ExperienceLevelServiceBean implements ExperienceLevelService {
*/
private void createExperienceLevel(Integer level, Long experienceNeeded) {
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);
}
}
@@ -32,6 +32,7 @@ public class ExperienceLevelServiceBean implements ExperienceLevelService {
*/
@Override
public void createLevelsUntil(Integer level) {
log.info("Creating experience levels until level {}.", level);
createExperienceLevel(0, 0L);
long experience = 0L;
for (int i = 1; i < level; i++) {

View File

@@ -59,6 +59,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Transactional
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)));
ARole loadedRole = roleManagementService.findRole(roleId);
experienceRoleManagementService.removeAllRoleAssignmentsForLevelInServer(experienceLevel, loadedRole.getServer());
@@ -87,6 +88,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
self.persistData(calculationResults, roleId)
);
} else {
log.info("Roles does not have any active users, no need to remove them.");
experienceRoleManagementService.unsetRole(roleInServer);
return CompletableFuture.completedFuture(null);
}
@@ -98,6 +100,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Transactional
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);
experienceRoleManagementService.unsetRole(roleInServer);
userExperienceService.syncRolesInStorage(results.getObjects());
@@ -115,6 +118,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
if(roles == null || roles.isEmpty()) {
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;
for (AExperienceRole experienceRole : roles) {
if(currentLevel >= experienceRole.getLevel().getLevel()) {
@@ -128,6 +132,7 @@ public class ExperienceRoleServiceBean implements ExperienceRoleService {
@Override
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);
roles = roles.stream().filter(role -> role.getLevel().getLevel() > startLevel.getLevel()).collect(Collectors.toList());
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.experience.models.database.AUserExperience;
import dev.sheldan.abstracto.experience.service.management.UserExperienceManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -16,6 +17,7 @@ import java.util.HashMap;
import java.util.Optional;
@Component
@Slf4j
public class HasLevelCondition implements SystemCondition {
public static final String USER_ID_VARIABLE = "userId";
@@ -29,15 +31,18 @@ public class HasLevelCondition implements SystemCondition {
@Override
public boolean checkCondition(ConditionContextInstance conditionContext) {
HashMap<String, Object> parameters = conditionContext.getParameters();
Long userId = (Long) parameters.get(USER_ID_VARIABLE);
Integer level = (Integer) parameters.get(LEVEL_VARIABLE);
log.info("Evaluating has level condition.");
Optional<AUserInAServer> userInServerOptional = userInServerManagementService.loadUserConditional(userId);
if(userInServerOptional.isPresent()) {
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);
return user.getCurrentLevel() != null && user.getCurrentLevel().getLevel() >= level;
}
log.info("No user experience object was found. Evaluating to 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.experience.models.database.ADisabledExpRole;
import dev.sheldan.abstracto.experience.repository.DisabledExpRoleRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class DisabledExpRoleManagementServiceBean implements DisabledExpRoleManagementService {
@Autowired
@@ -21,7 +23,7 @@ public class DisabledExpRoleManagementServiceBean implements DisabledExpRoleMana
.builder()
.role(role)
.build();
log.info("Adding disabled exp role {} for server {}.", role.getId(),role.getServer().getId());
return disabledExpRoleRepository.save(newRole);
}

View File

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

View File

@@ -31,13 +31,14 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
*/
@Override
public void removeAllRoleAssignmentsForLevelInServer(AExperienceLevel level, AServer server) {
log.trace("Removing all role assignments for level {}.", level.getLevel());
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));
}
@Override
public void unsetRole(AExperienceRole role) {
log.info("Deleting experience role {} in server {}.", role.getId(), role.getRoleServer().getId());
experienceRoleRepository.delete(role);
}
@@ -82,7 +83,9 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
public AExperienceRole setLevelToRole(AExperienceLevel level, ARole role) {
Optional<AExperienceRole> byRoleServerAndRoleOptional = getRoleInServerOptional(role);
AExperienceRole experienceRole;
log.info("Setting role {} in server {} to level {}.", role.getId(), role.getServer().getId(), level);
if(byRoleServerAndRoleOptional.isPresent()) {
log.trace("Role already existed. Updating.");
experienceRole = byRoleServerAndRoleOptional.get();
experienceRole.setLevel(level);
} else {
@@ -92,6 +95,7 @@ public class ExperienceRoleManagementServiceBean implements ExperienceRoleManage
.roleServer(role.getServer())
.role(role)
.build();
log.trace("Role did not exist. Creating new.");
experienceRole = experienceRoleRepository.save(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.AUserExperience;
import dev.sheldan.abstracto.experience.repository.UserExperienceRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;
@@ -15,7 +16,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Optional;
@Slf4j
@Component
public class UserExperienceManagementServiceBean implements UserExperienceManagementService {
@@ -48,6 +49,7 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage
*/
@Override
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)));
return AUserExperience
.builder()
@@ -65,37 +67,6 @@ public class UserExperienceManagementServiceBean implements UserExperienceManage
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
public List<AUserExperience> findLeaderBoardUsersPaginated(AServer aServer, Integer start, Integer 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.service.management.ExperienceLevelManagementService;
import dev.sheldan.abstracto.experience.service.management.ExperienceRoleManagementService;
import dev.sheldan.abstracto.test.MockUtils;
import net.dv8tion.jda.api.entities.Role;
import org.junit.Assert;
import org.junit.Test;
@@ -52,10 +51,12 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Mock
private ExperienceRoleServiceBean self;
@Mock
private AServer server;
@Test
public void testSettingRoleToLevelWithoutOldUsers() {
AServer server = MockUtils.getServer();
Integer levelCount = 10;
AExperienceLevel level = AExperienceLevel.builder().experienceNeeded(10L).level(levelCount).build();
Role roleToChange = Mockito.mock(Role.class);
@@ -73,7 +74,6 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Test
public void testUnsetRoleInDb() {
AServer server = MockUtils.getServer();
Integer levelCount = 10;
AExperienceLevel level = AExperienceLevel.builder().experienceNeeded(10L).level(levelCount).build();
ARole roleToChange = getRole(1L, server);
@@ -89,7 +89,6 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Test
public void testSettingRoleToLevelExistingUsers() {
AServer server = MockUtils.getServer();
Integer levelCount = 10;
AExperienceLevel level = AExperienceLevel.builder().experienceNeeded(10L).level(levelCount).build();
Role roleToChange = Mockito.mock(Role.class);
@@ -158,7 +157,6 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Test
public void testCalculatingLevelOfNextRole() {
AServer server = MockUtils.getServer();
when(experienceRoleManagementService.getExperienceRolesForServer(server)).thenReturn(getExperienceRoles());
AExperienceLevel levelToCheckFor = AExperienceLevel.builder().level(7).build();
AExperienceLevel levelOfNextRole = testingUnit.getLevelOfNextRole(levelToCheckFor, server);
@@ -167,7 +165,6 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
@Test
public void testCalculatingLevelOfNextRoleIfThereIsNone() {
AServer server = MockUtils.getServer();
when(experienceRoleManagementService.getExperienceRolesForServer(server)).thenReturn(getExperienceRoles());
AExperienceLevel levelToCheckFor = AExperienceLevel.builder().level(15).build();
AExperienceLevel levelOfNextRole = testingUnit.getLevelOfNextRole(levelToCheckFor, server);
@@ -182,7 +179,7 @@ public class ExperienceRoleServiceBeanTest extends ExperienceRelatedTest {
private AExperienceRole getExperienceRoleForLevel(int levelToBuild) {
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) {

View File

@@ -61,6 +61,7 @@ public class DisabledExpRoleManagementServiceBeanTest extends ExperienceRelatedT
}
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) {
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) {

View File

@@ -15,6 +15,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.domain.PageRequest;
@@ -47,7 +48,13 @@ public class UserExperienceManagementServiceBeanTest extends ExperienceRelatedTe
@Test
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());
AExperienceLevel startLevel = mockInitialLevel();
AUserExperience userInServer = testUnit.findUserInServer(user);
@@ -59,7 +66,13 @@ public class UserExperienceManagementServiceBeanTest extends ExperienceRelatedTe
@Test
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();
AUserExperience userInServer = testUnit.createUserInServer(user);
Assert.assertEquals(0L, userInServer.getExperience().longValue());
@@ -109,28 +122,6 @@ public class UserExperienceManagementServiceBeanTest extends ExperienceRelatedTe
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
public void testSaveUser() {
AUserInAServer user = AUserInAServer.builder().userInServerId(1L).userReference(AUser.builder().id(2L).build()).build();
@@ -147,28 +138,6 @@ public class UserExperienceManagementServiceBeanTest extends ExperienceRelatedTe
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() {
AUserExperience experience = 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);
/**
* 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}.
* @param server The {@link AServer} to retrieve the users for

View File

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

View File

@@ -28,7 +28,7 @@ public class UnMuteJob extends QuartzJobBean {
@Override
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);
}

View File

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

View File

@@ -50,6 +50,7 @@ public class MessageDeleteLogListener implements MessageDeletedListener {
MessageToSend message = templateService.renderEmbedTemplate(MESSAGE_DELETED_TEMPLATE, logModel);
postTargetService.sendEmbedInPostTarget(message, LoggingPostTarget.DELETE_LOG, messageFromCache.getServerId());
if(messageFromCache.getAttachmentUrls() != null){
log.trace("Notifying about deletions of {} attachments.", messageFromCache.getAttachmentUrls().size());
for (int i = 0; i < messageFromCache.getAttachmentUrls().size(); i++) {
MessageDeletedAttachmentLog log = MessageDeletedAttachmentLog
.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.DefaultConfigManagementService;
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.Value;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class WarnDecayConfigListener implements ServerConfigListener {
@Autowired
@@ -20,6 +22,7 @@ public class WarnDecayConfigListener implements ServerConfigListener {
@Override
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());
}
}

View File

@@ -19,8 +19,9 @@ public interface UserNoteRepository extends JpaRepository<UserNote, Long> {
@QueryHints(@QueryHint(name = org.hibernate.annotations.QueryHints.CACHEABLE, value = "true"))
List<UserNote> findByUser_ServerReference(AServer server);
@Override
@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) {
Optional<Guild> guildByIdOptional = botService.getGuildById(guildId);
if(guildByIdOptional.isPresent()) {
log.info("Banning user {} in guild {}.", userId, guildId);
return banUser(guildByIdOptional.get(), userId, reason);
} else {
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) {
log.info("Banning user {} in guild {}.", userId, guild.getId());
return guild.ban(userId.toString(), 0, reason).submit();
}
}

View File

@@ -134,12 +134,12 @@ public class MuteServiceBean implements MuteService {
throw new MuteRoleNotSetupException();
}
Member memberBeingMuted = userBeingMuted.getMember();
log.info("User {} mutes user {} until {}",
memberBeingMuted.getIdLong(), userMuting.getMember().getIdLong(), unMuteDate);
log.info("User {} mutes user {} in server {} until {}",
memberBeingMuted.getIdLong(), message.getServerId(), userMuting.getMember().getIdLong(), unMuteDate);
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 {
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<>();
AUserInAServer userInServerBeingMuted = userBeingMuted.getAUserInAServer();
@@ -159,15 +159,16 @@ public class MuteServiceBean implements MuteService {
}
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<>();
String muteNotificationMessage = templateService.renderTemplate(MUTE_NOTIFICATION_TEMPLATE, muteNotification);
CompletableFuture<Message> messageCompletableFuture = messageService.sendMessageToUser(memberBeingMuted.getUser(), muteNotificationMessage);
messageCompletableFuture.exceptionally(throwable -> {
TextChannel feedBackChannel = botService.getTextChannelFromServer(message.getServerId(), message.getChannelId());
feedBackChannel.sendMessage(throwable.getMessage()).submit().whenComplete((exceptionMessage, innerThrowable) ->
notificationFuture.complete(null)
);
feedBackChannel.sendMessage(throwable.getMessage()).submit().whenComplete((exceptionMessage, innerThrowable) -> {
notificationFuture.complete(null);
log.info("Successfully notified user {} in server {} about mute.", memberBeingMuted.getId(), memberBeingMuted.getGuild().getId());
});
return null;
});
messageCompletableFuture.thenAccept(message1 ->
@@ -226,7 +227,7 @@ public class MuteServiceBean implements MuteService {
@Override
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());
Long nextCounterValue = counterService.getNextCounterValue(server, MUTE_COUNTER_KEY);
context.setMuteId(nextCounterValue);
@@ -244,14 +245,14 @@ public class MuteServiceBean implements MuteService {
}
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);
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getContext().getServerId());
return FutureUtils.toSingleFutureGeneric(completableFutures);
}
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);
List<CompletableFuture<Message>> completableFutures = postTargetService.sendEmbedInPostTarget(message, MutingPostTarget.MUTE_LOG, muteLogModel.getServer().getId());
return FutureUtils.toSingleFutureGeneric(completableFutures);
@@ -313,7 +314,7 @@ public class MuteServiceBean implements MuteService {
@Override
@Transactional
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);
if(muteOptional.isPresent()) {
return endMute(muteOptional.get());
@@ -324,6 +325,7 @@ public class MuteServiceBean implements MuteService {
@Override
public void completelyUnMuteUser(AUserInAServer aUserInAServer) {
log.info("Completely unmuting user {} in server {}.", aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId());
List<Mute> allMutesOfUser = muteManagementService.getAllMutesOf(aUserInAServer);
allMutesOfUser.forEach(mute -> {
mute.setMuteEnded(true);

View File

@@ -25,6 +25,7 @@ import java.util.function.Consumer;
@Slf4j
public class PurgeServiceBean implements PurgeService {
public static final int PURGE_MAX_MESSAGES = 100;
@Autowired
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) {
int toDeleteInThisIteration;
int messageLimit = 100;
if(amountToDelete >= messageLimit){
toDeleteInThisIteration = messageLimit;
if(amountToDelete >= PURGE_MAX_MESSAGES){
toDeleteInThisIteration = PURGE_MAX_MESSAGES;
} 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<Long> statusMessageFuture = getOrCreatedStatusMessage(channel, totalCount, statusMessageId);
@@ -57,6 +58,7 @@ public class PurgeServiceBean implements PurgeService {
List<Message> messagesToDeleteNow = filterMessagesToDelete(retrievedHistory, purgedMember);
Long currentStatusMessageId = statusMessageFuture.get();
if(messagesToDeleteNow.size() == 0) {
log.warn("No messages found to delete, all were filtered.");
deletionFuture.completeExceptionally(new NoMessageFoundException());
channel.deleteMessageById(currentStatusMessageId).queueAfter(5, TimeUnit.SECONDS);
return;
@@ -64,7 +66,7 @@ public class PurgeServiceBean implements PurgeService {
Message latestMessage = messagesToDeleteNow.get(messagesToDeleteNow.size() - 1);
log.trace("Deleting {} messages directly", 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);
if (messagesToDeleteNow.size() > 1) {
bulkDeleteMessages(channel, deletionFuture, messagesToDeleteNow, consumer);
@@ -97,10 +99,12 @@ public class PurgeServiceBean implements PurgeService {
private CompletableFuture<Long> getOrCreatedStatusMessage(TextChannel channel, Integer totalCount, Long statusMessageId) {
CompletableFuture<Long> statusMessageFuture;
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();
MessageToSend messageToSend = templateService.renderTemplateToMessageToSend("purge_status_update", model);
statusMessageFuture = messageService.createStatusMessageId(messageToSend, channel);
} else {
log.trace("Using existing status message {}.", statusMessageId);
statusMessageFuture = CompletableFuture.completedFuture(statusMessageId);
}
return statusMessageFuture;
@@ -108,16 +112,20 @@ public class PurgeServiceBean implements PurgeService {
private List<Message> filterMessagesToDelete(List<Message> retrievedHistory, Member purgedMember) {
long twoWeeksAgo = TimeUtil.getDiscordTimestamp((System.currentTimeMillis() - (14 * 24 * 60 * 60 * 1000)));
log.trace("Filtering messages older than {}.", twoWeeksAgo);
List<Message> messagesToDeleteNow = new ArrayList<>();
for (Message messageObj : retrievedHistory) {
if (MiscUtil.parseSnowflake(messageObj.getId()) > twoWeeksAgo) {
if(purgedMember != null) {
if(messageObj.getAuthor().getIdLong() == purgedMember.getIdLong()) {
log.trace("Message {} is from filtered user {}. Purging.", messageObj.getId(), purgedMember.getIdLong());
messagesToDeleteNow.add(messageObj);
}
} else {
messagesToDeleteNow.add(messageObj);
}
} else {
log.trace("Message {} was older than {}. Not purging.", messageObj.getId(), twoWeeksAgo);
}
}
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) {
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) -> {
if (throwable != null) {
deletionFuture.completeExceptionally(throwable);
@@ -135,10 +144,11 @@ public class PurgeServiceBean implements PurgeService {
}
);
} else {
log.trace("Completed purging of {} messages.", totalCount);
channel.deleteMessageById(currentStatusMessageId).queueAfter(5, TimeUnit.SECONDS);
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();
MessageToSend finalUpdateMessage = templateService.renderTemplateToMessageToSend("purge_status_update", finalUpdateModel);
messageService.updateStatusMessage(channel, currentStatusMessageId, finalUpdateMessage);

View File

@@ -98,6 +98,8 @@ public class WarnServiceBean implements WarnService {
@Transactional
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 warningUser = userInServerManagementService.loadUser(context.getMember());
warnManagementService.createWarning(warnedUser, warningUser, context.getReason(), context.getWarnId());
@@ -109,6 +111,7 @@ public class WarnServiceBean implements WarnService {
public CompletableFuture<Void> decayWarningsForServer(AServer server) {
Long days = configService.getLongValue(WarningDecayFeature.DECAY_DAYS_KEY, server.getId());
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<Long> warningIds = flattenWarnings(warningsToDecay);
Long serverId = server.getId();
@@ -129,6 +132,7 @@ public class WarnServiceBean implements WarnService {
@Transactional
public void decayWarnings(List<Long> warningIds, Long serverId) {
Instant now = Instant.now();
log.info("Decaying {} warnings.", warningIds.size());
warningIds.forEach(warningId -> {
Optional<Warning> warningOptional = warnManagementService.findById(warningId, serverId);
warningOptional.ifPresent(warning ->
@@ -142,11 +146,13 @@ public class WarnServiceBean implements WarnService {
@Override
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.setDecayed(true);
}
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<>();
warningsToDecay.forEach(warning -> {
WarnDecayWarning warnDecayWarning = WarnDecayWarning
@@ -172,6 +178,7 @@ public class WarnServiceBean implements WarnService {
public CompletableFuture<Void> decayAllWarningsForServer(AServer server, boolean logWarnings) {
List<Warning> warningsToDecay = warnManagementService.getActiveWarningsInServerOlderThan(server, Instant.now());
List<Long> warnIds = flattenWarnings(warningsToDecay);
log.info("Decaying ALL warning in server {} with logging {}.", server.getId(), logWarnings);
Long serverId = server.getId();
if(logWarnings) {
return logDecayedWarnings(server, warningsToDecay).thenAccept(aVoid ->

View File

@@ -43,6 +43,7 @@ public class MuteRoleManagementServiceBean implements MuteRoleManagementService
public MuteRole setMuteRoleForServer(AServer server, ARole role) {
log.info("Setting muted role for server {} to role {}", server.getId(), role.getId());
if(!muteRoleForServerExists(server)) {
log.trace("Mute role did not exist yet, updating for server {}.", server.getId());
return createMuteRoleForServer(server, role);
} else {
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.moderation.models.database.UserNote;
import dev.sheldan.abstracto.moderation.repository.UserNoteRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class UserNoteManagementServiceBean implements UserNoteManagementService {
@Autowired
@@ -25,6 +27,7 @@ public class UserNoteManagementServiceBean implements UserNoteManagementService
@Override
public UserNote createUserNote(AUserInAServer aUserInAServer, String note) {
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);
UserNote newNote = UserNote
.builder()
@@ -38,13 +41,14 @@ public class UserNoteManagementServiceBean implements UserNoteManagementService
}
@Override
public void deleteNote(Long id) {
userNoteRepository.deleteById(id);
public void deleteNote(Long id, AServer server) {
log.info("Deleting user note with id {} in server {}.", id, server.getId());
userNoteRepository.deleteByUserNoteId_IdAndUserNoteId_ServerId(id, server.getId());
}
@Override
public boolean noteExists(Long id) {
return userNoteRepository.existsById(id);
public boolean noteExists(Long id, AServer server) {
return userNoteRepository.existsByUserNoteId_IdAndUserNoteId_ServerId(id, server.getId());
}
@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.repository.WarnRepository;
import dev.sheldan.abstracto.core.models.database.AUserInAServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -13,6 +14,7 @@ import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class WarnManagementServiceBean implements WarnManagementService {
@Autowired
@@ -20,6 +22,8 @@ public class WarnManagementServiceBean implements WarnManagementService {
@Override
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());
Warning warning = Warning.builder()
.reason(reason)
@@ -66,6 +70,7 @@ public class WarnManagementServiceBean implements WarnManagementService {
@Override
public void deleteWarning(Warning warning) {
log.info("Deleting warning with id {} in server {}.", warning.getWarnId().getId(), warning.getWarnId().getServerId());
warnRepository.delete(warning);
}

View File

@@ -37,16 +37,16 @@ public class DeleteNoteTest {
@Test
public void testDeleteExistingNote() {
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);
CommandTestUtilities.checkSuccessfulCompletion(result);
verify(userNoteManagementService, times(1)).deleteNote(NOTE_ID);
verify(userNoteManagementService, times(1)).deleteNote(NOTE_ID, parameters.getUserInitiatedContext().getServer());
}
@Test
public void testDeleteNotExistingNote() {
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");
CommandResult result = testUnit.execute(parameters);
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.utils.TimeUtil;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -77,6 +78,15 @@ public class PurgeServiceBeanTest {
@Mock
private AuditableRestAction deleteStatusAction;
@Mock
private Guild guild;
@Before
public void setup() {
when(textChannel.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("1");
}
@Test
public void testPurgeMessageViaStartMessage() {
Integer amountToDelete = 50;

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
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.AUserInAServer;
import dev.sheldan.abstracto.moderation.models.database.Warning;
@@ -130,6 +131,6 @@ public class WarnManagementServiceBeanTest {
}
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 {
UserNote createUserNote(AUserInAServer aUserInAServer, String note);
void deleteNote(Long id);
boolean noteExists(Long id);
void deleteNote(Long id, AServer server);
boolean noteExists(Long id, AServer server);
List<UserNote> loadNotesForUser(AUserInAServer aUserInAServer);
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.service.ModMailThreadService;
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.Message;
import org.springframework.beans.factory.annotation.Autowired;
@@ -32,6 +33,7 @@ import java.util.concurrent.CompletableFuture;
* the {@link net.dv8tion.jda.api.entities.MessageChannel}
*/
@Component
@Slf4j
public class Contact extends AbstractConditionableCommand {
@Autowired
@@ -53,6 +55,7 @@ public class Contact extends AbstractConditionableCommand {
// 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
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);
ModMailThread existingThread = modMailThreadManagementService.getOpenModMailThreadForUser(user);
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.modmail.service.ModMailThreadServiceBean;
import dev.sheldan.abstracto.templating.service.TemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -16,6 +17,7 @@ import static dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean.MOD
* makes things easier
*/
@Component
@Slf4j
public class ModMailConfigListener implements ServerConfigListener {
@@ -27,6 +29,7 @@ public class ModMailConfigListener implements ServerConfigListener {
@Override
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(), 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) {
AUser user = userManagementService.loadUser(message.getAuthor().getIdLong());
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
// 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);
modMailThreadService.relayMessageToModMailThread(existingThread, message, new ArrayList<>());
} else {
log.info("User {} does not have an open modmail thread. Crating prompt.", user.getId());
modMailThreadService.createModMailPrompt(user, message);
}
}

View File

@@ -30,6 +30,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
}
// all message must be from the same thread
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<>();
modMailMessages.forEach(modMailMessage -> {
ServerChannelMessage.ServerChannelMessageBuilder serverChannelMessageBuilder = ServerChannelMessage
@@ -37,6 +38,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
.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(Boolean.FALSE.equals(modMailMessage.getDmChannel())) {
log.trace("Message {} was from DM.", modMailMessage.getMessageId());
serverChannelMessageBuilder
.channelId(modMailMessage.getThreadReference().getChannel().getId())
.serverId(modMailMessage.getThreadReference().getServer().getId());
@@ -55,6 +57,7 @@ public class ModMailMessageServiceBean implements ModMailMessageService {
botService.getInstance().openPrivateChannelById(thread.getUser().getUserReference().getId()).queue(privateChannel -> {
Iterator<CompletableFuture<Message>> iterator = messageFutures.iterator();
messageIds.forEach(serverChannelMessage -> {
log.trace("Loading message {}.", serverChannelMessage.getMessageId());
// TODO fix out of order promises
// depending what the source of the message is, we need to fetch the message from the correct channel
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.modmail.config.ModMailFeatures;
import dev.sheldan.abstracto.modmail.service.management.ModMailRoleManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class ModMailRoleServiceBean implements ModMailRoleService {
@Autowired
@@ -22,15 +24,17 @@ public class ModMailRoleServiceBean implements ModMailRoleService {
@Override
public void addRoleToModMailRoles(ARole role) {
if(!modMailRoleManagementService.isRoleAlreadyAssigned(role, role.getServer())) {
modMailRoleManagementService.addRoleToModMailRoles(role, role.getServer());
log.info("Adding role {} to modmail roles in server {}.", role.getId(), role.getServer().getId());
if(!modMailRoleManagementService.isRoleAlreadyAssigned(role)) {
modMailRoleManagementService.addRoleToModMailRoles(role);
}
commandService.allowFeatureForRole(ModMailFeatures.MOD_MAIL, role);
}
@Override
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);
}
}

View File

@@ -38,7 +38,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@Component
@Slf4j
@@ -134,6 +133,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
Long serverId = aUserInAServer.getAUserInAServer().getServerReference().getId();
Long categoryId = configService.getLongValue(MODMAIL_CATEGORY, serverId);
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);
return textChannelFuture.thenCompose(channel -> {
@@ -153,12 +153,15 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
*/
@Transactional
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();
CompletableFuture<Void> headerFuture = sendModMailHeader(channel, aUserInAServer);
CompletableFuture<Void> userReplyMessage;
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());
} else {
log.trace("No initial message to send.");
userReplyMessage = CompletableFuture.completedFuture(null);
}
CompletableFuture notificationFuture;
@@ -175,9 +178,11 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Transactional
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);
ModMailThread thread = createThreadObject(channel, aUserInAServer);
if(initialMessage != null) {
log.trace("Adding initial message {} to modmail thread in channel {}.", initialMessage.getId(), channel.getId());
modMailMessageManagementService.addMessageToThread(thread, initialMessage, aUserInAServer, false, false);
}
}
@@ -188,7 +193,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
*/
@Transactional
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());
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
.builder()
.threadUser(aUserInAServer)
@@ -206,6 +213,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
* @return The created instance of {@link ModMailThread}
*/
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());
log.info("Creating mod mail thread in channel {} with db channel {}", channel.getIdLong(), channel2.getId());
return modMailThreadManagementService.createModMailThread(user, channel2);
@@ -213,6 +221,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override
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();
modMailFeatureValidator.validateModMailCategory(result, guild, categoryId);
if(result.getValidationResult()) {
@@ -226,6 +235,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
List<AUserInAServer> knownServers = userInServerManagementService.getUserInAllServers(user.getId());
// do nothing if we don't know the user
if(!knownServers.isEmpty()) {
log.info("There are {} shared servers between user and abstracto.", knownServers.size());
List<ServerChoice> availableGuilds = new ArrayList<>();
HashMap<String, AUserInAServer> choices = new HashMap<>();
for (int i = 0; i < knownServers.size(); i++) {
@@ -246,6 +256,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
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(availableGuilds.size() > 1) {
ModMailServerChooserModel modMailServerChooserModel = ModMailServerChooserModel
@@ -259,6 +270,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.setDescription(text)
.setAction(reactionEmote -> {
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);
FullUserInServer fullUser = FullUserInServer.builder().member(memberInServer).aUserInAServer(chosenServer).build();
self.createModMailThreadForUser(fullUser, initialMessage, initialMessage.getChannel(), true, new ArrayList<>()).exceptionally(throwable -> {
@@ -267,10 +279,12 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
});
})
.build();
log.trace("Displaying server choice message for user {} in channel {}.", user.getId(), initialMessage.getChannel().getId());
menu.display(initialMessage.getChannel());
} else if(availableGuilds.size() == 1) {
// if exactly one server is available, open the thread directly
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);
FullUserInServer fullUser = FullUserInServer.builder().member(memberInServer).aUserInAServer(chosenServer).build();
self.createModMailThreadForUser(fullUser, initialMessage, initialMessage.getChannel(), true, new ArrayList<>()).exceptionally(throwable -> {
@@ -278,6 +292,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
return null;
});
} else {
log.info("No server available to open a modmail thread in.");
// in case there is no server available, send an error message
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
*/
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());
List<ModMailThread> oldThreads = modMailThreadManagementService.getModMailThreadForUser(aUserInAServer.getAUserInAServer());
ModMailThreaderHeader header = ModMailThreaderHeader
@@ -308,11 +324,13 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override
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());
if(textChannelFromServer.isPresent()) {
TextChannel textChannel = textChannelFromServer.get();
return self.sendUserReply(textChannel, modMailThread, message, modMailThread.getUser());
} 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
// close the existing one, so the user can start a new one
self.closeModMailThreadInDb(modMailThread.getId());
@@ -348,6 +366,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.build();
subscribers.add(subscriber);
});
log.trace("Pinging {} subscribers for modmail thread {}.", subscriberList.size(), modMailThread.getId());
}
ModMailUserReplyModel modMailUserReplyModel = ModMailUserReplyModel
.builder()
@@ -359,7 +378,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
MessageToSend messageToSend = templateService.renderEmbedTemplate("modmail_user_message", modMailUserReplyModel);
List<CompletableFuture<Message>> completableFutures = channelService.sendMessageToSendToChannel(messageToSend, textChannel);
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 -> {
if(modMailThreadExists) {
self.postProcessSendMessages(textChannel, completableFutures.get(0).join());
@@ -378,6 +400,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(textChannel.getIdLong());
if(modMailThreadOpt.isPresent()) {
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);
// update the state of the thread
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.USER_REPLIED);
@@ -389,6 +412,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
@Override
public CompletableFuture<Void> relayMessageToDm(ModMailThread modMailThread, String text, Message message, boolean anonymous, MessageChannel feedBack, List<UndoActionInstance> undoActions) {
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());
if(userById != null) {
AUserInAServer moderator = userInServerManagementService.loadUser(message.getMember());
@@ -406,6 +430,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.anonymous(anonymous)
.threadUser(fullThreadUser);
if(anonymous) {
log.trace("Message is sent anonymous.");
modMailModeratorReplyModelBuilder.moderator(botService.getBotInGuild(modMailThread.getServer()));
} else {
Member moderatorMember = botService.getMemberInServer(moderator);
@@ -441,6 +466,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
).toCompletableFuture().thenCompose(o -> o);
} else {
log.trace("Not logging modmail thread {}.", modMailThreadId);
return self.afterSuccessfulLog(modMailThreadId, notifyUser, undoActions);
}
}
@@ -456,6 +482,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
*/
@Transactional
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 {
CompletableFutureList<Message> list = self.logModMailThread(modMailThreadId, messages, note, undoActions);
return list.getMainFuture().thenCompose(avoid -> {
@@ -485,6 +512,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
if(modMailThreadOpt.isPresent()) {
if(notifyUser) {
log.trace("Notifying user about the closed modmail thread {}.", modMailThreadId);
ModMailThread modMailThread = modMailThreadOpt.get();
User user = botService.getMemberInServer(modMailThread.getUser()).getUser();
HashMap<String, String> closingMessage = new HashMap<>();
@@ -494,6 +522,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
self.deleteChannelAndClose(modMailThreadId, undoActions)
);
} else {
log.trace("NOT Notifying user about the closed modmail thread {}.", modMailThreadId);
return deleteChannelAndClose(modMailThreadId, undoActions);
}
} else {
@@ -515,6 +544,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
ModMailThread modMailThread = modMailThreadOpt.get();
String failureMessage = "Failed to delete text channel containing mod mail thread {}";
try {
log.trace("Deleting channel {} which contained the modmail thread {}.", modMailThread.getChannel().getId(), modMailThreadId);
return channelService.deleteTextChannel(modMailThread.getChannel()).thenAccept(avoid -> {
undoActions.clear();
self.closeModMailThreadInDb(modMailThreadId);
@@ -546,7 +576,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
*/
@Transactional
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);
if(modMailThreadOpt.isPresent()) {
ModMailThread modMailThread = modMailThreadOpt.get();
@@ -554,8 +584,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
messages.forEach(future -> {
try {
if(!future.isCompletedExceptionally()) {
Message loadedMessage = future.get();
Message loadedMessage = future.join();
if(loadedMessage != null) {
log.info("Logging message {} in modmail thread {}.", loadedMessage.getId(), modMailThreadId);
ModMailMessage modmailMessage = modMailThread.getMessages()
.stream()
.filter(modMailMessage -> modMailMessage.getMessageId().equals(loadedMessage.getIdLong()))
@@ -569,10 +600,9 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.build();
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) {
log.error("Failed handle the loaded messages.", e);
}
@@ -585,10 +615,10 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
.closedThread(modMailThread)
.note(note)
.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);
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(self.sendMessagesToPostTarget(modMailThread, loggedMessages));
return new CompletableFutureList<>(completableFutures);
@@ -625,6 +655,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
public List<CompletableFuture<Message>> sendMessagesToPostTarget(ModMailThread modMailThread, List<ModMailLoggedMessageModel> loadedMessages) {
List<CompletableFuture<Message>> messageFutures = new ArrayList<>();
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);
List<CompletableFuture<Message>> logFuture = postTargetService.sendEmbedInPostTarget(messageToSend, ModMailPostTargets.MOD_MAIL_LOG, modMailThread.getServer().getId());
messageFutures.addAll(logFuture);
@@ -645,6 +676,7 @@ public class ModMailThreadServiceBean implements ModMailThreadService {
Optional<ModMailThread> modMailThreadOpt = modMailThreadManagementService.getById(modMailThreadId);
if(modMailThreadOpt.isPresent()) {
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);
modMailThreadManagementService.setModMailThreadState(modMailThread, ModMailThreadState.MOD_REPLIED);
} 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.ModMailThread;
import dev.sheldan.abstracto.modmail.repository.ModMailMessageRepository;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -11,6 +12,7 @@ import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class ModMailMessageManagementServiceBean implements ModMailMessageManagementService {
@Autowired
@@ -26,6 +28,8 @@ public class ModMailMessageManagementServiceBean implements ModMailMessageManage
.threadReference(modMailThread)
.anonymous(anonymous)
.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);
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.modmail.models.database.ModMailRole;
import dev.sheldan.abstracto.modmail.repository.ModMailRoleRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class ModMailRoleManagementServiceBean implements ModMailRoleManagementService {
@Autowired
private ModMailRoleRepository modMailRoleRepository;
@Override
public void addRoleToModMailRoles(ARole role, AServer server) {
public void addRoleToModMailRoles(ARole role) {
ModMailRole roleToAdd = ModMailRole
.builder()
.role(role)
.server(server)
.server(role.getServer())
.build();
log.info("Adding role {} in server {} to modmail roles.", role.getId(), role.getServer());
modMailRoleRepository.save(roleToAdd);
}
@Override
public void removeRoleFromModMailRoles(ARole role, AServer server) {
modMailRoleRepository.deleteByServerAndRole(server, role);
public void removeRoleFromModMailRoles(ARole role) {
modMailRoleRepository.deleteByServerAndRole(role.getServer(), role);
}
@Override
@@ -36,7 +39,7 @@ public class ModMailRoleManagementServiceBean implements ModMailRoleManagementSe
}
@Override
public boolean isRoleAlreadyAssigned(ARole role, AServer server) {
return modMailRoleRepository.existsByServerAndRole(server, role);
public boolean isRoleAlreadyAssigned(ARole 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.ModMailThreadSubscriber;
import dev.sheldan.abstracto.modmail.repository.ModMailSubscriberRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class ModMailSubscriberManagementServiceBean implements ModMailSubscriberManagementService {
@Autowired
@@ -34,12 +36,16 @@ public class ModMailSubscriberManagementServiceBean implements ModMailSubscriber
.threadReference(modMailThread)
.build();
log.info("Creating subscription for user {} in server {} for modmail thread {}.",
aUserInAServer.getUserReference().getId(), aUserInAServer.getServerReference().getId(), modMailThread.getId());
modMailSubscriberRepository.save(subscriber);
return subscriber;
}
@Override
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);
}
}

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.ModMailThreadState;
import dev.sheldan.abstracto.modmail.repository.ModMailThreadRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -15,6 +16,7 @@ import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class ModMailThreadManagementServiceBean implements ModMailThreadManagementService {
@Autowired
@@ -92,6 +94,9 @@ public class ModMailThreadManagementServiceBean implements ModMailThreadManageme
.updated(Instant.now())
.build();
log.info("Create modmail thread in channel {} for user {} in server {}.",
channel.getId(), userInAServer.getUserReference().getId(), userInAServer.getServerReference().getId());
modMailThreadRepository.save(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.service.ConfigService;
import dev.sheldan.abstracto.modmail.service.ModMailThreadServiceBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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
*/
@Component
@Slf4j
public class ModMailCategoryDelayedAction implements DelayedAction {
@Autowired
@@ -25,6 +27,7 @@ public class ModMailCategoryDelayedAction implements DelayedAction {
@Override
public void execute(DelayedActionConfig 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());
}

View File

@@ -80,9 +80,11 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
if(configManagementService.configExists(user.getGuildId(), ModMailThreadServiceBean.MODMAIL_CATEGORY)) {
Guild guild = botService.getGuildByIdNullable(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);
model.setCategory(category);
}
log.info("Executing mod mail category setup for server {}.", user.getGuildId());
String messageText = templateService.renderTemplate(messageTemplateKey, model);
AChannel channel = channelManagementService.loadChannel(user.getChannelId());
CompletableFuture<SetupStepResult> future = new CompletableFuture<>();
@@ -96,6 +98,7 @@ public class ModMailCategorySetupBean implements ModMailCategorySetup {
Message message = event.getMessage();
// this checks whether or not the user wanted to cancel the setup
if(checkForExit(message)) {
log.info("User {} wants to exit modmail category setup for server {}.", user.getUserId(), user.getGuildId());
result = SetupStepResult.fromCancelled();
} else {
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
modMailFeatureValidator.validateModMailCategory(featureValidationResult, guild, categoryId);
if(Boolean.TRUE.equals(featureValidationResult.getValidationResult())) {
log.trace("Given category {} maps to a valid category in server {}.", categoryId, guild.getId());
ModMailCategoryDelayedActionConfig build = ModMailCategoryDelayedActionConfig
.builder()
.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.modmail.models.template.ModMailCategoryValidationErrorModel;
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.Guild;
import org.springframework.beans.factory.annotation.Autowired;
@@ -21,6 +22,7 @@ import java.util.Optional;
* are used to fully validate the mod mail feature.
*/
@Component
@Slf4j
public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
@Autowired
@@ -44,7 +46,9 @@ public class ModMailFeatureValidatorBean implements ModMailFeatureValidator {
if(guildById.isPresent()) {
Guild guild = guildById.get();
boolean checkSucceeded = featureValidatorService.checkSystemConfig(ModMailThreadServiceBean.MODMAIL_CATEGORY, server, validationResult);
log.trace("Validating the modmail category for server {}.", server.getId());
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());
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
* is already present.
* @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
* 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 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
@@ -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}
* @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}
*/
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.utility.config.features.UtilityFeature;
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.stereotype.Component;
@@ -21,6 +22,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class ServerInfo extends AbstractConditionableCommand {
@Autowired
@@ -30,6 +32,7 @@ public class ServerInfo extends AbstractConditionableCommand {
public CompletableFuture<CommandResult> executeAsync(CommandContext commandContext) {
ServerInfoModel model = (ServerInfoModel) ContextConverter.fromCommandContext(commandContext, ServerInfoModel.class);
model.setGuild(commandContext.getGuild());
log.info("Displaying serverinfo for server {}", commandContext.getGuild().getId());
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel("serverinfo_response", model, commandContext.getChannel()))
.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.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.template.commands.ShowAvatarModel;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -22,6 +23,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class ShowAvatar extends AbstractConditionableCommand {
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();
Member memberToShow = parameters.size() == 1 ? (Member) parameters.get(0) : commandContext.getUserInitiatedContext().getMember();
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);
return FutureUtils.toSingleFutureGeneric(channelService.sendEmbedTemplateInChannel(SHOW_AVATAR_RESPONSE_TEMPLATE, model, commandContext.getChannel()))
.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.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.template.commands.UserInfoModel;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -24,6 +25,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class UserInfo extends AbstractConditionableCommand {
@Autowired
@@ -42,6 +44,7 @@ public class UserInfo extends AbstractConditionableCommand {
Member memberToShow = parameters.size() == 1 ? (Member) parameters.get(0) : commandContext.getAuthor();
UserInfoModel model = (UserInfoModel) ContextConverter.slimFromCommandContext(commandContext, UserInfoModel.class);
if(!memberToShow.hasTimeJoined()) {
log.info("Force reloading member {} in guild {} for user info.", memberToShow.getId(), memberToShow.getGuild().getId());
return botService.forceReloadMember(memberToShow).thenCompose(member -> {
model.setMemberInfo(member);
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.template.commands.reminder.ReminderModel;
import dev.sheldan.abstracto.utility.service.ReminderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -23,6 +24,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class Remind extends AbstractConditionableCommand {
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());
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()))
.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.ContextConverter;
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.utils.FutureUtils;
import dev.sheldan.abstracto.utility.config.features.UtilityFeature;
import dev.sheldan.abstracto.utility.models.database.Reminder;
import dev.sheldan.abstracto.utility.models.template.commands.reminder.RemindersModel;
import dev.sheldan.abstracto.utility.service.management.ReminderManagementService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -21,6 +23,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class Reminders extends AbstractConditionableCommand {
public static final String REMINDERS_RESPONSE_TEMPLATE = "reminders_response";
@@ -33,9 +36,11 @@ public class Reminders extends AbstractConditionableCommand {
@Override
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);
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()))
.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.models.template.commands.SuggestionLog;
import dev.sheldan.abstracto.utility.service.SuggestionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -21,6 +22,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class Accept extends AbstractConditionableCommand {
@Autowired
@@ -32,6 +34,7 @@ public class Accept extends AbstractConditionableCommand {
List<Object> parameters = commandContext.getParameters().getParameters();
Long suggestionId = (Long) parameters.get(0);
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);
return suggestionService.acceptSuggestion(suggestionId, text, suggestionModel)
.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.models.template.commands.SuggestionLog;
import dev.sheldan.abstracto.utility.service.SuggestionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -21,6 +22,7 @@ import java.util.List;
import java.util.concurrent.CompletableFuture;
@Component
@Slf4j
public class Reject extends AbstractConditionableCommand {
@Autowired
@@ -32,6 +34,7 @@ public class Reject extends AbstractConditionableCommand {
List<Object> parameters = commandContext.getParameters().getParameters();
Long suggestionId = (Long) parameters.get(0);
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);
return suggestionService.rejectSuggestion(suggestionId, text, suggestionModel)
.thenApply(aVoid -> CommandResult.fromSuccess());

View File

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

View File

@@ -39,14 +39,17 @@ public class MessageEmbedListener implements MessageReceivedListener {
String messageRaw = message.getContentRaw();
List<MessageEmbedLink> links = messageEmbedService.getLinksInMessage(messageRaw);
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();
for (MessageEmbedLink messageEmbedLink : links) {
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;
}
messageRaw = messageRaw.replace(messageEmbedLink.getWholeUrl(), "");
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 -> {
log.error("Error when embedding link for message {}", message.getId(), throwable);
return null;
@@ -60,6 +63,8 @@ public class MessageEmbedListener implements MessageReceivedListener {
@Transactional
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);
}

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.service.management.MessageEmbedPostManagementService;
import lombok.extern.slf4j.Slf4j;
import net.dv8tion.jda.api.entities.Emote;
import net.dv8tion.jda.api.entities.MessageReaction;
import net.dv8tion.jda.api.events.message.guild.react.GuildMessageReactionAddEvent;
import org.springframework.beans.factory.annotation.Autowired;
@@ -45,8 +44,6 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener
Long guildId = message.getServerId();
AEmote aEmote = emoteService.getEmoteOrDefaultEmote(REMOVAL_EMOTE, guildId);
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)) {
Optional<EmbeddedMessage> embeddedMessageOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId());
if(embeddedMessageOptional.isPresent()) {
@@ -55,12 +52,18 @@ public class MessageEmbedRemovalReactionListener implements ReactedAddedListener
if(embeddedMessage.getEmbeddedUser().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 ->{
Optional<EmbeddedMessage> innerOptional = messageEmbedPostManagementService.findEmbeddedPostByMessageId(message.getMessageId());
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);
MessageReaction.ReactionEmote reactionEmote = addedReaction.getReactionEmote();
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);
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) {
starboardPost.setIgnored(false);
// TODO handle futures correctly
starboardService.updateStarboardPost(starboardPost, message, userExceptAuthor);
if(adding) {
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);
MessageReaction.ReactionEmote reactionEmote = removedReaction.getReactionEmote();
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());
Optional<CachedReaction> reactionOptional = emoteService.getReactionFromMessageByEmote(message, aEmote);
handleStarboardPostChange(message, reactionOptional.orElse(null), userRemoving, false);
@@ -158,6 +159,8 @@ public class StarboardListener implements ReactedAddedListener, ReactedRemovedLi
Optional<StarboardPost> starboardPostOptional = starboardPostManagementService.findByMessageId(message.getMessageId());
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);
completelyRemoveStarboardPost(starboardPost);
});

View File

@@ -77,7 +77,7 @@ public class RemindServiceBean implements ReminderService {
user.getUserReference().getId(), user.getServerReference().getId(), remindAt);
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(() -> {
try {
self.executeReminder(reminder.getId());
@@ -86,10 +86,10 @@ public class RemindServiceBean implements ReminderService {
}
}, remindIn.toNanos(), TimeUnit.NANOSECONDS);
} else {
log.trace("Starting scheduled job to execute reminder.");
JobDataMap parameters = new JobDataMap();
parameters.putAsString("reminderId", reminder.getId());
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);
reminderManagementService.saveReminder(reminder);
}
@@ -105,7 +105,8 @@ public class RemindServiceBean implements ReminderService {
}
AServer server = reminderToRemindFor.getServer();
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());
if(guildToAnswerIn.isPresent()) {
Optional<TextChannel> channelToAnswerIn = botService.getTextChannelFromServerOptional(server.getId(), channel.getId());
@@ -133,9 +134,11 @@ public class RemindServiceBean implements ReminderService {
@Override
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.setReminded(true);
if(reminder.getJobTriggerKey() != null) {
log.trace("Stopping scheduled trigger {} for reminder {}.", reminder.getJobTriggerKey(), reminderId);
schedulerService.stopTrigger(reminder.getJobTriggerKey());
}
}

View File

@@ -32,7 +32,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
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());
Long starboardChannelId = starboard.getChannelReference().getId();
Long starredUserId = starredUser.getUserInServerId();
Long userReactingId = userReacting.getUserInServerId();
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 -> {
log.error("Failed to create starboard post for message {} in channel {} in server {}", message.getMessageId(), message.getChannelId(), message.getServerId(), throwable);
return null;
@@ -101,29 +99,25 @@ public class StarboardServiceBean implements StarboardService {
}
@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));
try {
AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId);
Message message1 = completableFutures.get(0).get();
AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage
.builder()
.messageId(message1.getIdLong())
.channel(starboardChannel)
.server(starboardChannel.getServer())
.build();
StarboardPost starboardPost = starboardPostManagementService.createStarboardPost(message, innerStarredUser, aServerAChannelMessage);
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());
}
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();
AChannel starboardChannel = channelManagementService.loadChannel(starboardChannelId);
Message message1 = completableFutures.get(0).join();
AServerAChannelMessage aServerAChannelMessage = AServerAChannelMessage
.builder()
.messageId(message1.getIdLong())
.channel(starboardChannel)
.server(starboardChannel.getServer())
.build();
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()) {
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);
});
}
private StarboardPostModel buildStarboardPostModel(CachedMessage message, Integer starCount) {
@@ -150,20 +144,14 @@ public class StarboardServiceBean implements StarboardService {
@Override
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());
MessageToSend messageToSend = templateService.renderEmbedTemplate(STARBOARD_POST_TEMPLATE, starboardPostModel);
List<CompletableFuture<Message>> futures = postTargetService.editOrCreatedInPostTarget(post.getStarboardMessageId(), messageToSend, StarboardPostTarget.STARBOARD, message.getServerId());
Long starboardPostId = post.getId();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(aVoid -> {
try {
Optional<StarboardPost> innerPost = starboardPostManagementService.findByStarboardPostId(starboardPostId);
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();
}
Optional<StarboardPost> innerPost = starboardPostManagementService.findByStarboardPostId(starboardPostId);
innerPost.ifPresent(starboardPost -> starboardPostManagementService.setStarboardPostMessageId(starboardPost, futures.get(0).join().getIdLong()));
}).exceptionally(throwable -> {
log.error("Failed to update starboard post {}.", post.getId(), throwable);
return null;
@@ -173,6 +161,7 @@ public class StarboardServiceBean implements StarboardService {
@Override
public void deleteStarboardMessagePost(StarboardPost message) {
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());
}

View File

@@ -71,19 +71,23 @@ public class SuggestionServiceBean implements SuggestionService {
suggestionLog.setText(text);
MessageToSend messageToSend = templateService.renderEmbedTemplate(SUGGESTION_LOG_TEMPLATE, suggestionLog);
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);
return CompletableFuture.allOf(completableFutures.toArray(new CompletableFuture[0])).thenCompose(aVoid -> {
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> secondReaction = messageService.addReactionToMessageWithFuture(SUGGESTION_NO_EMOTE, guildId, message);
return CompletableFuture.allOf(firstReaction, secondReaction).thenAccept(aVoid1 ->
self.persistSuggestionInDatabase(member, text, message, newSuggestionId)
);
return CompletableFuture.allOf(firstReaction, secondReaction).thenAccept(aVoid1 -> {
log.trace("Reaction added to message {} for suggestion {}.", message.getId(), newSuggestionId);
self.persistSuggestionInDatabase(member, text, message, newSuggestionId);
});
});
}
@Transactional
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);
}
@@ -91,6 +95,7 @@ public class SuggestionServiceBean implements SuggestionService {
public CompletableFuture<Void> acceptSuggestion(Long suggestionId, String text, SuggestionLog suggestionLog) {
Suggestion suggestion = suggestionManagementService.getSuggestion(suggestionId).orElseThrow(() -> new SuggestionNotFoundException(suggestionId));
suggestionManagementService.setSuggestionState(suggestion, SuggestionState.ACCEPTED);
log.info("Accepting suggestion {} in server {}.", suggestionId, suggestion.getServer().getId());
return updateSuggestion(text, suggestionLog, suggestion);
}
@@ -99,6 +104,7 @@ public class SuggestionServiceBean implements SuggestionService {
Long channelId = suggestion.getChannel().getId();
Long originalMessageId = suggestion.getMessageId();
Long serverId = suggestion.getServer().getId();
log.info("Updated posted suggestion {} in server {}.", suggestion.getId(), suggestion.getServer().getId());
suggestionLog.setOriginalChannelId(channelId);
suggestionLog.setOriginalMessageId(originalMessageId);
@@ -130,6 +136,7 @@ public class SuggestionServiceBean implements SuggestionService {
public CompletableFuture<Void> updateSuggestionMessageText(String text, SuggestionLog suggestionLog, Message message) {
Optional<MessageEmbed> embedOptional = message.getEmbeds().stream().filter(embed -> embed.getDescription() != null).findFirst();
if(embedOptional.isPresent()) {
log.info("Updating the text of the suggestion {} in server {}.", suggestionLog.getSuggestionId(), message.getGuild().getId());
MessageEmbed suggestionEmbed = embedOptional.get();
suggestionLog.setReason(text);
suggestionLog.setText(suggestionEmbed.getDescription());
@@ -143,9 +150,10 @@ public class SuggestionServiceBean implements SuggestionService {
}
@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));
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)
.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);
}
@@ -68,6 +72,7 @@ public class MessageEmbedPostManagementServiceBean implements MessageEmbedPostMa
@Override
@Transactional
public void deleteEmbeddedMessage(EmbeddedMessage embeddedMessage) {
log.info("Deleting embedded message {}.", embeddedMessage.getEmbeddingMessageId());
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.utility.models.database.Reminder;
import dev.sheldan.abstracto.utility.repository.ReminderRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -12,6 +13,7 @@ import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class ReminderManagementServiceBean implements ReminderManagementService {
@Autowired
@@ -29,6 +31,8 @@ public class ReminderManagementServiceBean implements ReminderManagementService
.targetDate(timeToBeRemindedAt)
.messageId(messageId)
.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);
return reminder;
@@ -42,6 +46,7 @@ public class ReminderManagementServiceBean implements ReminderManagementService
@Override
public void setReminded(Reminder reminder) {
reminder.setReminded(true);
log.info("Setting reminder {} to reminded.", reminder.getId());
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.utility.models.database.StarboardPost;
import dev.sheldan.abstracto.utility.repository.StarboardPostRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -17,6 +18,7 @@ import java.util.List;
import java.util.Optional;
@Component
@Slf4j
public class StarboardPostManagementServiceBean implements StarboardPostManagementService {
@Autowired
@@ -38,6 +40,10 @@ public class StarboardPostManagementServiceBean implements StarboardPostManageme
.starboardChannel(starboardPost.getChannel())
.starredDate(Instant.now())
.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);
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.StarboardPostReactionRepository;
import dev.sheldan.abstracto.utility.repository.converter.StarStatsUserConverter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
@Slf4j
public class StarboardPostReactorManagementServiceBean implements StarboardPostReactorManagementService {
@Autowired
@@ -28,16 +30,19 @@ public class StarboardPostReactorManagementServiceBean implements StarboardPostR
.starboardPost(post)
.reactor(user)
.build();
log.info("Persisting the reactor {} for starboard post {} in server {}.", user.getUserReference().getId(), post.getId(), user.getServerReference().getId());
repository.save(reactor);
}
@Override
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);
}
@Override
public void removeReactors(StarboardPost post) {
log.info("Removing all {} reactors from starboard post {}", post.getReactions().size(), post.getId());
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.SuggestionState;
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.Message;
import org.springframework.beans.factory.annotation.Autowired;
@@ -17,6 +18,7 @@ import java.time.Instant;
import java.util.Optional;
@Component
@Slf4j
public class SuggestionManagementServiceBean implements SuggestionManagementService {
@Autowired
@@ -51,6 +53,8 @@ public class SuggestionManagementServiceBean implements SuggestionManagementServ
.channel(channel)
.messageId(message.getIdLong())
.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);
return suggestion;
}
@@ -64,6 +68,7 @@ public class SuggestionManagementServiceBean implements SuggestionManagementServ
@Override
public void setSuggestionState(Suggestion suggestion, SuggestionState newState) {
suggestion.setState(newState);
log.info("Setting suggestion {} to state {}.", suggestion.getId(), newState);
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.utility.StarboardFeatureValidator;
import dev.sheldan.abstracto.utility.service.StarboardServiceBean;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class StarboardFeatureValidatorService implements StarboardFeatureValidator {
@Autowired
@@ -22,6 +24,7 @@ public class StarboardFeatureValidatorService implements StarboardFeatureValidat
@Override
public void featureIsSetup(FeatureConfig featureConfig, AServer server, FeatureValidationResult validationResult) {
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++) {
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.CommandTestUtilities;
import dev.sheldan.abstracto.utility.models.template.commands.UserInfoModel;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import org.junit.Assert;
import org.junit.Test;
@@ -60,6 +61,7 @@ public class UserInfoTest {
CommandContext noParameters = CommandTestUtilities.getNoParameters();
when(noParameters.getAuthor().hasTimeJoined()).thenReturn(false);
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(self.sendResponse(eq(noParameters), modelArgumentCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(noParameters);
@@ -86,6 +88,7 @@ public class UserInfoTest {
when(member.hasTimeJoined()).thenReturn(false);
CommandContext parameters = CommandTestUtilities.getWithParameters(Arrays.asList(member));
Member loadedAuthor = Mockito.mock(Member.class);
when(member.getGuild()).thenReturn(Mockito.mock(Guild.class));
when(botService.forceReloadMember(member)).thenReturn(CompletableFuture.completedFuture(loadedAuthor));
when(self.sendResponse(eq(parameters), modelArgumentCaptor.capture())).thenReturn(CompletableFuture.completedFuture(null));
CompletableFuture<CommandResult> result = testUnit.executeAsync(parameters);

View File

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

View File

@@ -103,7 +103,6 @@ public class MessageEmbedRemovalReactionListenerTest {
AEmote reactedEmote = AEmote.builder().build();
when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote);
when(messageReaction.getReactionEmote()).thenReturn(reactionEmote);
when(botService.getEmote(serverId, reactedEmote)).thenReturn(Optional.of(emote));
when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(true);
EmbeddedMessage message = EmbeddedMessage
.builder()
@@ -134,7 +133,6 @@ public class MessageEmbedRemovalReactionListenerTest {
AEmote reactedEmote = AEmote.builder().build();
when(emoteService.getEmoteOrDefaultEmote(MessageEmbedRemovalReactionListener.REMOVAL_EMOTE, serverId)).thenReturn(reactedEmote);
when(messageReaction.getReactionEmote()).thenReturn(reactionEmote);
when(botService.getEmote(serverId, reactedEmote)).thenReturn(Optional.of(emote));
when(emoteService.isReactionEmoteAEmote(reactionEmote, reactedEmote)).thenReturn(wasCorrectEmote);
testUnit.executeReactionAdded(cachedMessage, messageReaction, userInAServer);
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.database.AChannel;
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.service.BotService;
import dev.sheldan.abstracto.core.service.ChannelService;
@@ -145,7 +146,11 @@ public class RemindServiceBeanTest {
AServer server = MockUtils.getServer();
AChannel aChannel = MockUtils.getTextChannel(server, 4L);
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));
Guild guildMock = Mockito.mock(Guild.class);
when(botService.getGuildById(server.getId())).thenReturn(Optional.of(guildMock));
@@ -157,8 +162,14 @@ public class RemindServiceBeanTest {
@Test
public void testExecuteReminderFromNotFoundGuild() {
AServer server = MockUtils.getServer();
AChannel aChannel = Mockito.mock(AChannel.class);
when(aChannel.getId()).thenReturn(9L);
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(botService.getGuildById(server.getId())).thenReturn(Optional.empty());
testUnit.executeReminder(reminderId);

View File

@@ -131,7 +131,7 @@ public class StarboardServiceBeanTest {
when(configService.getLongValue("starLvl2", server.getId())).thenReturn(2L);
when(emoteService.getUsableEmoteOrDefault(server.getId(), "star2")).thenReturn("b");
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();
Assert.assertEquals(1, starboardPostModels.size());
StarboardPostModel usedModel = starboardPostModels.get(0);
@@ -162,7 +162,7 @@ public class StarboardServiceBeanTest {
AUserInAServer secondStarrerUserObj = MockUtils.getUserObject(secondStarrerUserId, server);
when(userInServerManagementService.loadUserConditional(secondStarrerUserId)).thenReturn(Optional.of(secondStarrerUserObj));
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());
List<AUserInAServer> addedReactors = userInAServerArgumentCaptor.getAllValues();
Assert.assertEquals(secondStarrerUserId, addedReactors.get(0).getUserInServerId());
@@ -178,6 +178,8 @@ public class StarboardServiceBeanTest {
Long oldPostId = 36L;
AUserInAServer starredUser = MockUtils.getUserObject(5L, server);
Long channelId = 10L;
AChannel sourceChannel = Mockito.mock(AChannel.class);
when(sourceChannel.getServer()).thenReturn(server);
CachedMessage message = CachedMessage
.builder()
.authorId(starredUser.getUserReference().getId())
@@ -185,7 +187,7 @@ public class StarboardServiceBeanTest {
.channelId(channelId)
.build();
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();
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)));
@@ -207,6 +209,7 @@ public class StarboardServiceBeanTest {
StarboardPost post = StarboardPost
.builder()
.starboardChannel(channel)
.sourceChanel(channel)
.starboardMessageId(messageId)
.build();
testUnit.deleteStarboardMessagePost(post);
@@ -275,6 +278,6 @@ public class StarboardServiceBeanTest {
Long secondStarrerUserId = 2L;
List<Long> userExceptAuthorIds = Arrays.asList(secondStarrerUserId, userReacting.getUserReference().getId());
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
public void testCreateSuggestion() {
Member member = Mockito.mock(Member.class);
when(member.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("5");
String text = "text";
Message message = Mockito.mock(Message.class);
Long suggestionId = 3L;
@@ -172,6 +174,8 @@ public class SuggestionServiceBeanTest {
MessageEmbed embed = Mockito.mock(MessageEmbed.class);
when(embed.getDescription()).thenReturn("description");
Message suggestionMessage = Mockito.mock(Message.class);
when(suggestionMessage.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("8");
when(suggestionMessage.getEmbeds()).thenReturn(Arrays.asList(embed));
MessageToSend updatedMessage = MessageToSend.builder().build();
when(templateService.renderEmbedTemplate(eq(SuggestionServiceBean.SUGGESTION_LOG_TEMPLATE), any(SuggestionLog.class))).thenReturn(updatedMessage);

View File

@@ -59,7 +59,7 @@ public class StarboardPostReactorManagementServiceBeanTest {
@Test
public void testRemoveReactors() {
StarboardPost post = StarboardPost.builder().build();
StarboardPost post = StarboardPost.builder().reactions(new ArrayList<>()).build();
testUnit.removeReactors(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.database.Suggestion;
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.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
@@ -48,12 +49,15 @@ public class SuggestionManagementServiceBeanTest {
AServer server = MockUtils.getServer();
AUserInAServer userInAServer = MockUtils.getUserObject(5L, server);
String text = "text";
Guild guild = Mockito.mock(Guild.class);
Message message = Mockito.mock(Message.class);
MessageChannel messageChannel = Mockito.mock(MessageChannel.class);
when(messageChannel.getIdLong()).thenReturn(CHANNEL_ID);
when(message.getChannel()).thenReturn(messageChannel);
when(message.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("8");
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);
Assert.assertEquals(SuggestionState.NEW, createdSuggestion.getState());
Assert.assertEquals(userInAServer.getUserInServerId(), createdSuggestion.getSuggester().getUserInServerId());
@@ -66,10 +70,13 @@ public class SuggestionManagementServiceBeanTest {
AServer server = MockUtils.getServer();
AUserInAServer userInAServer = MockUtils.getUserObject(5L, server);
String text = "text";
Guild guild = Mockito.mock(Guild.class);
Message message = Mockito.mock(Message.class);
MessageChannel messageChannel = Mockito.mock(MessageChannel.class);
when(messageChannel.getIdLong()).thenReturn(CHANNEL_ID);
when(message.getChannel()).thenReturn(messageChannel);
when(message.getGuild()).thenReturn(guild);
when(guild.getId()).thenReturn("5");
when(userInServerManagementService.loadUser(member)).thenReturn(userInAServer);
long suggestionId = 1L;
Suggestion createdSuggestion = testUnit.createSuggestion(member, text, message, suggestionId);

View File

@@ -33,6 +33,8 @@ public class StarboardFeature implements FeatureConfig {
return Arrays.asList(starboardFeatureValidator);
}
// TODO add missing system config keys
@Override
public List<String> getRequiredEmotes() {
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
@Setter
@SuperBuilder
// TODO change user initiated context so slim context, and remove database entities referenced
public class SuggestionLog extends UserInitiatedServerContext {
private Long suggestionId;
private SuggestionState state;